Security
Protect credentials, validate tool execution, handle sensitive data, and configure requests securely with `@orcushq/deepseek`.
@orcushq/deepseek sends requests to DeepSeek Web using credentials supplied by your application. The SDK does not sign in to your account or automatically refresh expired sessions. Your application remains responsible for credential storage, permissions, and sensitive data handling.
Protect your credentials
Every request requires both dsSessionId and authorization. Load them from environment variables or a secrets manager. The SDK checks that the values are present, but this does not guarantee that DeepSeek accepts them.
DEEPSEEK_SESSION_ID=your_ds_session_id_valueDEEPSEEK_AUTHORIZATION=your_authorization_valueimport 'dotenv/config'import { DeepSeekWeb } from '@orcushq/deepseek' const dsSessionId = process.env.DEEPSEEK_SESSION_IDconst authorization = process.env.DEEPSEEK_AUTHORIZATION if (!dsSessionId || !authorization) { throw new Error( 'Set DEEPSEEK_SESSION_ID and DEEPSEEK_AUTHORIZATION in .env', )} const model = new DeepSeekWeb({ model: 'deepseek-v3', dsSessionId, authorization,}) const response = await model.invoke('Explain API security in one sentence.') console.log(response.content)The environment-variable check prevents the example from running when either value is missing. A separate test confirmed that constructing a client with empty credentials and invoking it raises DeepSeekAuthenticationError.
- Never hardcode credentials or commit them to version control.
- Never expose credentials in frontend bundles, screenshots, logs, or public issue reports.
- Do not print authentication headers or the complete client configuration.
- If credentials are exposed, obtain replacement credentials and update your application configuration.
- Treat clients created with
withConfig()as sensitive because they retain configured credentials.
The SDK does not automatically refresh expired credentials. HTTP 401 responses are mapped to DeepSeekAuthenticationError, while HTTP 403 responses are mapped to DeepSeekAuthorizationError. See Authentication and Find required keys.
Protect error details and logs
includeErrorBody defaults to false, but it is not a complete data-redaction mechanism. DeepSeekApiError can retain upstream messages in apiMessage and details.apiMessage. HTTP 200 error envelopes can also expose upstream messages.
Response metadata may contain the raw SSE transcript in metadata.raw. Citations can contain titles, snippets, URLs, and other upstream data. Review these fields before storing or logging them.
- Redact sensitive fields before logging errors or responses.
- Avoid logging
error.details,error.apiMessage,metadata.raw, or complete response objects without reviewing their contents. - Keep
includeErrorBodydisabled in production unless additional response details are necessary and handled safely. - Avoid returning raw upstream errors directly to end users.
Error-body handling is not redaction
Setting `includeErrorBody: false` does not remove every upstream message from error properties or HTTP 200 error-envelope messages. Sanitize sensitive information before logging or forwarding errors.
Custom headers and transport
defaultHeaders adds custom headers to transport requests. The SDK also constructs its own authentication and protocol headers. Do not use defaultHeaders to override authorization, cookie, origin, referer, or x-ds-pow-response.
The protocol-header builder filters protected headers, but defaultHeaders is also merged separately by the transport. Case-variant names can bypass the first filtering step and result in duplicate values. For example, lowercase authorization or cookie entries can conflict with the SDK-generated credentials.
- Use
userAgentandacceptLanguagefor their respective headers instead of duplicating them indefaultHeaders. - Use only trusted implementations for
fetchImpl. - A custom fetch implementation can redirect requests, log sensitive headers, or ignore cancellation signals.
- Do not assume timeouts or cancellation work correctly when a custom fetch implementation ignores
AbortSignal.
Do not override authentication headers
Mixed or duplicate authentication headers can cause requests to fail and may expose credentials when an untrusted custom transport is used.
Execute tools safely
Tool calling uses prompt-based orchestration. Each tool has a name, description, Zod schema, and application function. The SDK validates model-generated arguments against the schema before executing the function, but application-level authorization remains your responsibility.
import 'dotenv/config'import { z } from 'zod'import { DeepSeekWeb } from '@orcushq/deepseek' const dsSessionId = process.env.DEEPSEEK_SESSION_IDconst authorization = process.env.DEEPSEEK_AUTHORIZATION if (!dsSessionId || !authorization) { throw new Error( 'Set DEEPSEEK_SESSION_ID and DEEPSEEK_AUTHORIZATION in .env', )} const model = new DeepSeekWeb({ model: 'deepseek-v3', dsSessionId, authorization,}) let toolExecutionCount = 0 const allowedServices = ['payments', 'search'] as const const tools = [ { name: 'get_service_status', description: 'Get demo status for an allowed service. Use this tool when asked about payments or search service status.', schema: z.object({ service: z.enum(allowedServices), }).strict(), func: async (input: { service: (typeof allowedServices)[number] }) => { if (!allowedServices.includes(input.service)) { throw new Error('Service is not allowed.') } toolExecutionCount++ console.log('[Tool executed]', input.service) // Demo data; no external service is accessed. return { service: input.service, status: 'operational', } }, },] try { const response = await model.invoke( 'Use get_service_status to check the payments service. Then summarize its result in one sentence.', { tools, maxToolIterations: 3, }, ) console.log('Final response:', response.content) console.log('Tool execution count:', toolExecutionCount) if (toolExecutionCount > 0) { console.log('PASS: Registered tool executed.') } else { console.error('FAIL: Tool execution was not observed.') process.exitCode = 1 }} catch (error) { console.error('Tool security test failed:', error) process.exitCode = 1}This example was tested successfully: missing credentials were rejected, and the registered get_service_status function executed once for the payments request. The returned status is demonstration data, not a live service health check.
- Expose only tools your application is willing to execute.
- Validate tool arguments at runtime.
- Check the caller’s permissions before performing sensitive actions.
- Never pass model-generated arguments directly to shell commands, SQL queries, or dynamic code execution without appropriate validation and parameterization.
- Require approval for consequential actions such as payments, deleting data, or sending messages.
- Apply timeouts and resource limits to external tool functions.
- Sanitize tool errors because their messages may be returned to the model.
The SDK does not sandbox tool functions or enforce application-level authorization. Tool results are also untrusted input and may contain text intended to influence subsequent model responses.
Tool support
Non-empty tool definitions are supported by `invoke()`. Streaming and batch operations do not support tool execution. See [Tool calling](/docs/deepseek/tools) for the implementation-specific API.
Treat model output as untrusted
Model-generated text, thinking content, citations, and tool results are data, not trusted instructions. Structured output is extracted and validated locally using Zod; validation checks the output shape, not its correctness or safety.
- Escape model-generated content before rendering it as HTML.
- Validate generated values again before using them in security-sensitive operations.
- Do not trust URLs or citation content automatically.
- Do not treat a system message as an enforced security boundary; the SDK flattens message roles into a prompt.
- Keep privileged actions behind application-side authorization checks.
Structured-output validation failures may include a preview of the generated text and validation issues. Review these details before sending them to logs or error-reporting services. See Structured output.
Conversation and batch data
Conversation identifiers, prompts, raw response metadata, and batch errors may contain sensitive application data. Protect them using the same standards as other application records.
- Do not mix users or tenants with different authorization scopes in a single batch.
- Remember that batch items share the configured credentials and invocation options.
- Inspect
.failuresand.errorswhen handlingBatchAggregateError; do not assume it contains successful results. - Treat
chatSessionIdandparentMessageIdas potentially sensitive identifiers.
Network access and unsupported inputs
The default request path uses the configured DeepSeek Web endpoints. The SDK does not fetch citation URLs or remote images. Image inputs are unsupported and rejected with DeepSeekUnsupportedFeatureError.
If your application fetches or renders URLs returned by the model, validate them independently and apply appropriate destination, redirect, timeout, and size restrictions. These checks are application responsibilities, not protections provided by the SDK.
Retries and resource limits
The default request timeout is 60 seconds, and the default turn-level retry policy allows three attempts. Streaming timeouts cover waiting for response headers rather than the complete stream. The SDK does not impose general input/output size limits or per-tool execution timeouts.
A streaming retry can emit text that was already delivered during a previous failed attempt. If your application displays chunks immediately, repeated text may appear. Consider disabling retries for the call or buffering output until completion before displaying it.
Security checklist
- Credentials are stored securely and never committed or logged.
- Error properties and raw response metadata are redacted before logging.
- Custom fetch implementations and headers are trusted and reviewed.
- Tool arguments are validated and every action is authorized by the application.
- Model output and structured values are validated at security-sensitive boundaries.
- Citation URLs are validated before the application fetches them.
- Streaming retry behavior and resource limits are accounted for.