Security

Vetting an Inference Provider's SDK Before You Add It

Antonio Evans9 min read

A developer's desk seen from above: an open laptop showing a terminal with a package manifest and a source file, a printed checklist with four columns labeled Dependencies, Telemetry, Retries, Errors.
Key points

Key points

  1. 1Read the SDK's manifest to see the full transitive dependency tree, and flag any bundled HTTP client or native binary you did not choose yourself.
  2. 2Grep the source for every outbound URL, telemetry endpoint and log call so you know exactly what data leaves your process and where it goes.
  3. 3Confirm retry defaults: attempt caps, exponential backoff with jitter, respect for the Retry-After header, and a clear split between retriable and fatal errors.
  4. 4Check that errors are typed and carry status codes, request IDs and partial results, and that timeouts and streaming cancellation are configurable, not hardcoded.

Why an AI model SDK deserves the same scrutiny as a payment library

A model SDK is not a thin wrapper. It usually carries its own HTTP transport, its own retry loop, its own serialization format, its own logging and, increasingly, its own agent loop that can call tools. When you add it to an agent, you are handing a third-party package the ability to make network calls on your behalf, spend your money per token, and write text into your logs that may include customer data. That is the same trust boundary you already apply to a payment or authentication library.

NIST's Secure Software Development Framework exists precisely to make that kind of trust explicit. The framework organizes secure development into four practice groups (Prepare the Organization, Protect the Software, Produce Well-Secured Software and Respond to Vulnerabilities), and its acquirer-facing purpose is to give buyers and suppliers a shared vocabulary for procurement and due diligence (NIST SSDF project page). The published framework recommends that acquirers express their secure development requirements to third-party suppliers using SSDF conventions, and that producers maintain provenance and vulnerability monitoring for third-party components (NIST SP 800-218). A draft revision of the framework continues that line for suppliers (NIST SSDF 1.2 draft announcement), and CISA publishes the same guidance for buyers and integrators (CISA SSDF V1.1 resource).

A vendor SDK fails those expectations most often in quiet ways. A helper package gets compromised, a maintainer account is taken over, or a dependency's install script runs before you read a line of code. The xz Utils backdoor, SolarWinds and Codecov are the canonical examples where malicious code arrived through a trusted, legitimate channel (Apiiro supply chain glossary). The NCSC's dependency guidance makes the same point for package ecosystems generally: automation, implicit trust and scale mean one poisoned package can spread across many organizations before anyone notices (NCSC dependency blog). An AI model SDK sits in exactly that sweet spot, because it is new enough that most teams install it with one command and never open the source.

The audit below is deliberately narrow enough to finish in an afternoon. It has four parts, then a second pass on the things that bite later (timeouts, streaming, credentials). The decision rule at the end tells you what to do when a part fails.

Part 1: Dependencies, read the manifest before the docs

Start with the manifest, not the README. In Python that is pyproject.toml, setup.py or requirements.txt; in JavaScript it is package.json and the lockfile. What you are looking for is not the list of direct dependencies, which the vendor shows you, but the transitive graph underneath it.

Three things should stop you and make you look harder:

  • A bundled or pinned HTTP client. If the SDK requires a specific major version of requests, httpx, axios or urllib3, it may override your own transport, ignore your proxy settings or bypass your instrumented client. That is how an SDK becomes an unmonitored network boundary.
  • Native bindings. Packages with compiled extensions (crypto libraries, tokenizers, ONNX runtimes) ship binaries that a source review cannot fully inspect. Check whether wheels are published with hashes, whether builds are reproducible, and whether an install script runs arbitrary code.
  • Install-time scripts. Node and Python both allow code to execute on install (NCSC dependency blog). An install hook that downloads a model file or fetches configuration at install time is doing a network call before your review even begins.

Then freeze the graph. Version locking is not glamorous, but it is the control that makes the rest of the audit repeatable. A lock file records every direct and transitive package at an exact resolved version with a content hash, so a restore either reproduces that graph or fails loudly (NuGet version locking write-up). The same principle carries across ecosystems: pin, commit the lock, and run CI in a locked mode so that a dependency change is a reviewable diff rather than a silent drift.

A practical rule for the graph itself: any transitive package that arrives with the SDK and cannot be justified by reading its name is a package you should be able to name and explain. If you cannot explain why foo-utils is in your tree, treat it as suspicious until you can. The academic literature on supply chain risk now catalogues nineteen distinct attack types mapped to twenty-five controls (Journal of Information Security and Applications taxonomy); you do not need to apply all of them to one SDK, but dependency confusion and typosquatting are the two that hit model SDKs most often.

Part 2: Telemetry, find every URL and every log call

This is the part most teams skip. An AI SDK can send more data outbound than any other library you own: prompts, completions, token counts, error traces and sometimes the full request and response bodies.

Do the grep yourself. For a Python package:

# outbound endpoints and hosts
grep -RnE "https?://|requests\.(get|post|put)|httpx\.|urllib" ./sdk_package
# logging and print calls
grep -RnE "logging\.|logger\.|print\(|console\.log" ./sdk_package
# environment variables and credential reads
grep -RnE "os\.environ|getenv|process\.env" ./sdk_package

For a JavaScript package, substitute fetch( and axios for the HTTP patterns. Triage the output by host. The API endpoint is expected. A second host, a crash-reporting service or a version-check URL is a decision for your security team, not the vendor's default. Any log line that writes the request body, a prompt, or a response will land in your aggregator, and from there in whoever has access to it.

Pay attention to where credentials are read and stored. An SDK that pulls keys from os.environ is normal and good. An SDK that writes the key to a config file, a cache directory or an error payload is not. A common failure mode in agent SDKs is an exception handler that serializes the whole request object, headers included, into the log stream.

What to look forWhy it mattersAction if present
Extra hosts in the sourceData may leave to a vendor or third-party serviceConfirm ownership and purpose, or block at egress
Request or response bodies in logsPrompts and outputs may contain customer dataRedact before your logger sees them
Credentials in exceptionsA log aggregator becomes a secret storePatch or wrap the client, and rotate keys
Version or usage pingsAdds a second failure domain to every callDisable by config, or accept explicitly
Install-time downloadsCode runs before you can review itInstall in a sandbox, never with production keys

A useful habit is to run the SDK once in an isolated container with egress monitoring and a dummy key, then read the connection log. That gives you a factual list of what it contacted, which is more reliable than any marketing page about privacy.

Part 3: Retries, attempt caps and jitter are not optional

Model APIs fail transiently. Rate limits, timeouts and 5xx responses are normal. The question is whether the SDK's retry loop is safe for an agent that may itself be running many concurrent calls.

Check four things in the retry code:

  1. A hard attempt cap. Retries without a cap turn a rate-limit storm into a self-inflicted denial of service. A small default (a handful of attempts) is reasonable; unlimited or configurable-to-unlimited is not.
  2. Exponential backoff with jitter. Straight exponential backoff keeps clients synchronized, which recreates the thundering herd on every retry window. Jitter spreads them out. Retry frameworks treat exponential backoff with jitter as the baseline practice for exactly this reason (retry logic guide).
  3. Respect for Retry-After. If the server tells the client when to come back, the SDK should use that value. Ignoring it means the retries start before the window opens.
  4. A retriable versus fatal split. 429 and 5xx responses are usually retriable. 400 and 401 are not, and retrying them burns velocity and money for no result. A good SDK classifies errors before acting; a bad one retries everything.

Also check what the SDK retries: the request or the whole logical operation. If a tool-calling loop is retried wholesale, a side effect (a write, a payment, a ticket) may execute twice. That is the difference between an idempotent retry and a duplicate action in production.

Part 4: Errors and timeouts, does the failure carry information

An error that says "request failed" is useless in an incident. You want typed exceptions, an HTTP status where one applies, a request ID for the provider's support team, and any partial result the response already produced before the failure.

The minimum bar for a model SDK in an agent:

  • Typed, distinguishable errors (rate limit, authentication, validation, server, network) rather than a single generic exception.
  • Status code and request or trace ID on every network-derived error.
  • Partial output preserved for streaming failures, so an agent can resume or report rather than lose work.
  • A configurable timeout, with separate connect and read values if available.
  • Explicit cancellation for streams, so a stopped tool call closes the connection instead of leaving a generator hanging.

If timeouts are hardcoded, the SDK decides how long your request may hang, not you. If streaming cancellation is absent, an abandoned stream may keep consuming quota until it finishes. Both are direct costs.

NIST's practice groups map cleanly onto this checklist: protecting the software means controlling how components talk to the network and where secrets live, while producing well-secured software means tested error paths and configuration (Black Duck SSDF summary). You can borrow that structure for the review itself: record each finding under a practice so the audit reads like a control check rather than a set of opinions.

The decision rule, and how to wrap a failing SDK

Use a two-part test.

  • Pass: every outbound host is explainable, retries are capped with jitter and Retry-After handling, errors are typed with status codes and request IDs, timeouts and cancellation are configurable, credentials are read from the environment and never logged, and the version graph is locked and hash-verified.
  • Fail: any of those is missing, undocumented or hardcoded.

If any part fails, do not necessarily reject the SDK. Treat it as an untrusted network boundary and wrap it. The wrapper does four things: own the transport and proxy settings, normalize errors into your own typed exceptions, enforce your retry policy in one place instead of trusting the library's, and redact before logging. That wrapper is also where you inject your own request ID, which makes vendor support conversations tractable.

For teams running several model providers, this is where a single interface pays for itself: one transport, one retry policy, one error taxonomy and one logging path, regardless of vendor. Quanta Inference provides text, image, video, audio and embedding models through one OpenAI-compatible API key with prepaid US-dollar pricing, which lets you keep your own wrapper and swap the backend (Quanta Inference).

Smaller teams without a security reviewer can get the same answer from a structured conversation about their goals and constraints rather than a checklist read cold (Quanta Consulting).

Worked example: the same call under three SDK defaults

Consider an agent that makes 1,000 model calls in a batch, and a provider that starts returning 429 responses at 20 percent of requests for ten minutes. The naive SDK retries each 429 five times immediately, with no cap on concurrency and no jitter. The load almost triples: 200 failed calls become up to 1,000 extra attempts, which pushes the rate limiter into sustained rejection and holds your batch open for the whole window.

The second SDK caps attempts at five, backs off exponentially with jitter, and honors Retry-After. Attempts also arrive spread across the window rather than in a synchronized burst. Once the limiter lifts, the queue drains, and the batch finishes on a predictable timeline.

The third SDK is your wrapper around either of the first two. It enforces the cap, jitter and Retry-After handling in your code, emits a metric per attempt, and logs the request ID on each failure. The SDK's defaults stop mattering, which is the point: you reviewed the vendor once, and the behavior you reviewed is the behavior that ships.

BehaviorNaive defaultReviewed defaultWrapped client
Retry capNone or highSmall, documentedEnforced in wrapper
BackoffFixed or plain exponentialExponential with jitterOwned by you
Retry-AfterIgnoredHonoredHonored
Failure visibilityGeneric errorTyped plus request IDTyped plus your trace
Duplicate side effectsPossibleGuardedGuarded by idempotency key

The numbers are illustrative, but the direction holds: retry behavior is a policy decision, and the party that should own it is the party that knows its own traffic.

FAQ

FAQ

Is it enough to check the SDK's changelog and security page?

No. A vendor page describes what the vendor chose to disclose. The manifest, the source and a single monitored run tell you what the package actually does. Use the vendor's documentation to understand intent, and the source to verify it.

What if the SDK bundles its own HTTP client?

Assume it bypasses your own instrumentation, proxy and logging until proven otherwise. Confirm by running it in a sandbox with egress monitoring. If it does bypass your controls, either configure it to use your transport or wrap it.

How many retry attempts should an agent use?

There is no universal number. What matters is that the cap is small, documented, configurable and paired with jitter and Retry-After handling. Retries on a non-idempotent operation should be gated, not automatic.

Do I need to audit every transitive dependency, or only the direct ones?

You need to be able to name and explain every transitive package in the tree. That does not require reading each one line by line, but a package you cannot justify is a package you cannot defend in a review, and the lock file plus hash check is what keeps that answer stable over time.

Where do credentials usually leak in a model SDK?

In error paths and logs. Grep for exception serialization and log calls around the request object, and check whether the key is read from the environment or persisted to disk. Treat any writing of credentials to a file, cache or payload as a defect and fix it before adoption.

Sources

Sources

  1. Secure Software Development Framework (SSDF)
  2. PDF Secure Software Development Framework (SSDF) Version 1.1
  3. Secure Software Development Framework (SSDF) Version 1.2 is ...
  4. NIST SP 800-218, Secure Software Development Framework V1.1 - CISA
  5. Software Supply Chain Attacks
  6. Software supply chain attacks: check your dependencies
  7. NuGet Version Locking and Your Build Becomes Stable
  8. Software supply chain: A taxonomy of attacks, mitigations ...
  9. Mastering Retry Logic Agents: A Deep Dive into 2025 Best ...
  10. Implementing NIST SSDF: Best Practices for Secure Software ...
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles