Conversation
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com> Signed-off-by: RinkalBhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: RinkalBhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: RinkalBhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: RinkalBhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: RinkalBhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: RinkalBhojani <rinkal.bhojani@ayanworks.com>
…de credential payload Signed-off-by: RinkalBhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: RinkalBhojani <rinkal.bhojani@ayanworks.com>
Feat/support for x509 certs Mdoc support moved signer option to credential level
Signed-off-by: Rinkal Bhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: Rinkal Bhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
feat: mdoc support
* updated creat x509 method and few types Signed-off-by: Rinkal Bhojani <rinkal.bhojani@ayanworks.com> * corrected mapper function for mdoc payload Signed-off-by: Rinkal Bhojani <rinkal.bhojani@ayanworks.com> --------- Signed-off-by: Rinkal Bhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: Rinkal Bhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: Rinkal Bhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Feat/oid4vc presentation
Signed-off-by: Rinkal Bhojani <rinkal.bhojani@ayanworks.com>
Signed-off-by: Rinkal Bhojani <rinkal.bhojani@ayanworks.com>
fix: Added getTrustedCert function and refactored code
Signed-off-by: shitrerohit <rohit.shitre@ayanworks.com>
Signed-off-by: shitrerohit <rohit.shitre@ayanworks.com>
Signed-off-by: shitrerohit <rohit.shitre@ayanworks.com>
Signed-off-by: Rinkal Bhojani <rinkal.bhojani@ayanworks.com>
…n sessions Signed-off-by: Rinkal Bhojani <rinkal.bhojani@ayanworks.com>
…-response feat:API for verify the authorization response
Signed-off-by: shitrerohit <rohit.shitre@ayanworks.com>
* fix: update credo version to 0.6.2 Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: update credo version Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> --------- Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
feat: added x509 certificates logic with auth
* fix: add polygon resolver and registrar Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: restore polygon module Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: linting Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: polygon controller Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: take polygon config from env for setupAgent Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: update rpc url Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: polygon signature issue and schema creation Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: polygon package update Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: remove unnecessary logs Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> --------- Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com>
* fix: did and schema controller Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: naming convention and remove comments Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: formatting Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: remove unused param Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: credential definition controller Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> * fix: error when cred-def failure Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com> --------- Signed-off-by: Krishna Waske <krishna.waske@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
Signed-off-by: Tipu_Singh <tipu.singh@ayanworks.com>
…ogic refactor: update get x509 certs logic
• **Total HIGH/CRITICAL Vulnerabilities:** 3 • **OS Vulnerabilities:** 3 (HIGH: 2, CRITICAL: 1) • **Application Vulnerabilities:** 0 ### REMAINING VULNERABILITIES | Library | CVE ID | Severity | Installed Version | Fixed Version | Description | |---------|--------|----------|-------------------|---------------|-------------| | libc-bin | CVE-2026-0861 | HIGH | 2.36-9+deb12u13 | - | glibc: Integer overflow in memalign leads to heap corruption | | libc6 | CVE-2026-0861 | HIGH | 2.36-9+deb12u13 | - | glibc: Integer overflow in memalign leads to heap corruption | | zlib1g | CVE-2023-45853 | CRITICAL | 1:1.2.13.dfsg-1 | - | zlib: integer overflow and resultant heap-based buffer overflow | ### FIXED VULNERABILITIES • **axios:** Updated to 1.13.5 (CVE-2026-25639) • **flatted:** Updated to 3.4.0 (CVE-2026-32141) • **undici:** Updated to 6.24.0 (CVE-2026-1526, CVE-2026-1528, CVE-2026-2229) • **All Node.js packages:** 0 vulnerabilities detected ### REMEDIATION STATUS • **97% vulnerability reduction** achieved • **All application-level vulnerabilities fixed** • **Remaining vulnerabilities are OS-level only** ### SECURITY ENHANCEMENTS IMPLEMENTED • Non-root user execution (appuser) • System package updates • CA certificates installed • Temporary files cleaned • Proper file permissions Signed-off-by: DeepakNemad <deepak.nemade@ayanworks.com>
|
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (1)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughConsolidates DIDComm migration, adds OpenID4VC holder/issuer/verifier and session APIs, implements X.509 certificate creation/import/trust flows and token/trust-service helpers, updates environment variables and Docker base image, and upgrades multiple Changes
Sequence Diagram(s)sequenceDiagram
actor Holder
participant Agent as Agent (Holder)
participant Issuer as Issuer Server
participant Auth as Authorization Server
Holder->>Agent: Resolve Credential Offer URI
Agent->>Issuer: Fetch Offer Details
Issuer-->>Agent: Offer (credentials, grants)
Agent-->>Holder: Present Offer
alt Pre-Authorized Grant
Holder->>Agent: Use Pre-Auth Code
Agent->>Issuer: Token Request with pre-auth
Issuer-->>Agent: Access Token
else Authorization Code Flow
Holder->>Auth: Authorize (user agent)
Auth-->>Holder: Authorization Code
Holder->>Agent: Provide Code + Verifier
Agent->>Auth: Token Request (code, verifier)
Auth-->>Agent: Access Token
end
Agent->>Issuer: Credential Request (binding proof: DID/x5c/JWK)
Issuer-->>Agent: Signed Credential (SD-JWT / mDoc)
Agent->>Holder: Store Credential
sequenceDiagram
actor User
participant VerifierAgent as Agent (Verifier)
participant Verifier as Verifier Server
participant Holder as Holder Agent
User->>Verifier: Request Proof (create session)
Verifier-->>User: Authorization Request URI
User->>Holder: Resolve Proof Request
Holder->>Verifier: Fetch Presentation Definition
Verifier-->>Holder: Presentation Definition
Holder->>Holder: Select Credentials & Build Presentation
Holder->>Verifier: Submit Authorization Response + Presentation
Verifier->>Verifier: Verify Presentation
Verifier-->>Holder: Verification Result
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 3
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/cli.ts (1)
176-194:⚠️ Potential issue | 🔴 CriticalThe
databaseproperty should bestorageto match@credo-ts/askar0.6.2 configuration.According to Credo documentation for
@credo-ts/askar0.6.2, wallet storage is configured viawalletConfig.storageproperty, notdatabase. The current code structure uses the incorrect property name. Change the property fromdatabase:tostorage:at line 179 to align with the expected AskarModuleConfigStoreOptions interface.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/cli.ts` around lines 176 - 194, The walletConfig object is using the wrong key name for Askar storage; rename the nested "database" property to "storage" inside walletConfig so it matches the `@credo-ts/askar` 0.6.2 AskarModuleConfigStoreOptions shape (update the object currently constructed for walletConfig in src/cli.ts: change the property named "database" to "storage" while keeping its inner keys host/connectTimeout/maxConnections/idleTimeout and credentials/account/password/adminAccount/adminPassword intact).src/controllers/didcomm/outofband/OutOfBandController.ts (1)
177-195:⚠️ Potential issue | 🟠 MajorDeserialize invitations by
@typeinstead of forcing the OOB class.The endpoint accepts both OOB and connection invitations per the documentation, but always constructs
DidCommOutOfBandInvitationfrom the raw body. This will reject connection invitations and incompletely parse OOB payloads (onlyhandshake_protocolsis remapped). UseJsonTransformer.fromJSON()with type-based routing to properly deserialize both invitation formats, similar to the pattern already used elsewhere in this file forDidCommMessage.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/didcomm/outofband/OutOfBandController.ts` around lines 177 - 195, The receiveInvitation handler currently always constructs a DidCommOutOfBandInvitation from the raw body, which rejects connection invitations and misses other OOB fields; instead, deserialize by `@type` using JsonTransformer.fromJSON and route to the correct class (e.g. DidCommOutOfBandInvitation vs the connection-invitation class used in this repo) before calling request.agent.modules.didcomm.oob.receiveInvitation. Update the logic in receiveInvitation (and use ReceiveInvitationProps as input) to inspect invitation["@type"] (or use the same type-based routing pattern used for DidCommMessage in this file), call JsonTransformer.fromJSON(invitation, TargetClass) to produce the proper instance, then pass that instance to didcomm.oob.receiveInvitation.
🟠 Major comments (23)
src/controllers/didcomm/credentials/CredentialController.ts-1-325 (1)
1-325:⚠️ Potential issue | 🟠 MajorAvoid committing entirely commented-out code.
The entire
CredentialControllerhas been commented out, removing DIDComm credential exchange endpoints (/didcomm/credentials/*) from the application. This is confirmed alongside the same issue inProofController.ts. No replacement handlers for these endpoints exist.Choose one of:
- Delete the file if credential exchange functionality is being removed
- Keep it active if this is work in progress
Commented-out code should not be committed to the main branch.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/didcomm/credentials/CredentialController.ts` around lines 1 - 325, The CredentialController class (CredentialController) and its methods (e.g., getAllCredentials, getW3cById, getCredentialById, proposeCredential, acceptProposal, createOffer, createOfferOob, acceptOffer, acceptRequest, acceptCredential, credentialFormData) and helper ensureLinkSecretExists are entirely commented out; either remove the file or restore it — to restore, uncomment the class and all methods, re-enable the imports at the top (W3cCredentialService, createPeerDidDocumentFromServices, PeerDidNumAlgo, Request/Req, tsoa decorators, injectables, SCOPES, ErrorHandlingService, AgentType, examples, types, OutOfBandController), ensure dependency names match (e.g., request.agent.modules.credentials, request.agent.dependencyManager.resolve(W3cCredentialService)), and run linter/tests to fix any missing types or imports; if functionality is intentionally removed, delete the file instead to avoid committing commented-out code.src/controllers/didcomm/proofs/ProofController.ts-1-283 (1)
1-283:⚠️ Potential issue | 🟠 MajorDo not commit entirely commented-out code.
The entire
ProofControllerhas been commented out rather than deleted or kept active. This creates inconsistencies:
- The README documents "Endpoints to create connections, issue credentials, and request proofs," but proof endpoints are not accessible via the REST API
- Proof protocols remain configured in the agent (
DidCommProofV1Protocol,DidCommProofV2Protocol)- The controller is not registered in routes.ts, so commenting it out effectively disables the API endpoints
- No documentation, TODO, or changelog entry explains why this was disabled
Either:
- Delete the file if DIDComm proofs functionality is being removed
- Keep it active and uncomment if still needed
- Document the change clearly in CHANGELOG with explanation
Commented-out code creates maintenance confusion and makes the intended API capabilities unclear to users and developers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/didcomm/proofs/ProofController.ts` around lines 1 - 283, The ProofController file is entirely commented out; either remove it or restore and register its routes and docs. If keeping functionality: uncomment and re-enable the ProofController class and its public methods (ProofController, getAllProofs, getProofById, proposeProof, acceptProposal, requestProof, createRequest, acceptRequest, acceptPresentation, proofFormData), ensure the controller is registered in routes.ts, and verify protocol registrations (DidCommProofV1Protocol/DidCommProofV2Protocol) and agent configuration remain consistent; if removing functionality: delete this file and remove any proof protocol registration (DidCommProofV1Protocol/DidCommProofV2Protocol) and related modules, then add a CHANGELOG entry and update the README to reflect the removal so docs, routes, and agent config stay aligned.src/controllers/auth/AuthController.ts-36-42 (1)
36-42:⚠️ Potential issue | 🟠 MajorAdd error handling and timeout for external HTTP call.
The
axios.postcall lacks error handling — network failures, timeouts, or non-2xx responses will propagate as unhandled errors, resulting in generic 500 responses. External calls should also have timeouts to prevent hanging requests.🔧 Proposed fix with error handling and timeout
+import { InternalServerError } from '../../errors' + const response = await axios.post<OrgTokenResponse>( `${trustServiceTokenUrl}`, { clientId: body.clientId, clientSecret: body.clientSecret }, - { headers: { 'Content-Type': 'application/json', accept: 'application/json' } }, + { + headers: { 'Content-Type': 'application/json', accept: 'application/json' }, + timeout: 10000, // 10 second timeout + }, - ) + ).catch((error) => { + const message = error.response?.data?.message || error.message || 'Failed to obtain token' + throw new InternalServerError(`Trust service error: ${message}`) + }) return response.data🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/auth/AuthController.ts` around lines 36 - 42, The axios.post call in AuthController (the request to trustServiceTokenUrl that returns OrgTokenResponse) needs a timeout and proper error handling: wrap the axios.post in a try/catch inside the method in AuthController.ts (where response.data is returned), add a timeout option (e.g., { timeout: 5000, headers: { ... } }) to the axios call, check response.status to ensure a 2xx before returning response.data, and in the catch block convert network/timeouts/non-2xx responses into a clear, handled error (log context including body.clientId and the caught error) or throw a controlled error type so the caller can return a meaningful HTTP response instead of an unhandled 500.src/controllers/didcomm/connections/ConnectionController.ts-132-139 (1)
132-139:⚠️ Potential issue | 🟠 MajorThis endpoint no longer matches its
invitationIdcontract.
findByInvitationDid(invitationId)switches the lookup from the created invitation ID to the invitation DID, while the route and method name still advertise an invitation ID / URL lookup. Existing clients will start seeing 404s or a different payload shape here unless the endpoint is renamed and its contract is updated accordingly.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/didcomm/connections/ConnectionController.ts` around lines 132 - 139, The endpoint Get('/didcomm/url/:invitationId') and method getInvitation incorrectly call request.agent.modules.didcomm.connections.findByInvitationDid(invitationId) which performs a DID lookup instead of an invitation ID/URL lookup; either update the call to the correct lookup (e.g., use a findByInvitationId or findByInvitationUrl method on request.agent.modules.didcomm.connections) or rename the route/method to reflect that it expects an invitation DID (and update request parameter name and docs), and ensure the NotFoundError message uses the matching identifier; adjust any response shape if the alternate lookup returns a different record type.src/cliAgent.ts-203-205 (1)
203-205:⚠️ Potential issue | 🟠 MajorExplicit
falsecan never disable connection auto-accept.
autoAcceptConnections || truecoerces a configuredfalseback totrueboth before and insidegetModules, so this setting is effectively impossible to turn off for either tenant or non-tenant agents.💡 Proposed fix
connections: { - autoAcceptConnections: autoAcceptConnections || true, + autoAcceptConnections, }, ... - autoAcceptConnections || true, + autoAcceptConnections ?? true, ... - autoAcceptConnections || true, + autoAcceptConnections ?? true,Also applies to: 441-467
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/cliAgent.ts` around lines 203 - 205, The connections.autoAcceptConnections is currently set with the expression autoAcceptConnections || true which forces false to true; update the logic wherever used (e.g., in the connections object at the construction site and inside getModules) to explicitly check for undefined/null instead of using || so a configured false is honored — for example, use a conditional like (autoAcceptConnections === undefined ? true : autoAcceptConnections) or Object.hasOwnProperty checks before defaulting; ensure the same change is applied to the other occurrence(s) referenced (lines 441-467) so tenant and non-tenant agents can disable auto-accept when set to false.src/controllers/openid4vc/holder/credentialBindingResolver.ts-37-43 (1)
37-43:⚠️ Potential issue | 🟠 MajorClamp and validate numeric
requestBatch.The 10-item cap is only enforced when
requestBatch === true. A numeric value like50will currently generate 50 keys, and0/ negative / fractional values can fall through to an empty request or an invalid array length at Line 55.💡 Proposed fix
+ if (typeof requestBatch === 'number' && (!Number.isInteger(requestBatch) || requestBatch < 1)) { + throw new Error('requestBatch must be a positive integer') + } + const batchSize = requestBatch === true ? Math.min(issuerMaxBatchSize, 10) : typeof requestBatch === 'number' - ? Math.min(issuerMaxBatchSize, requestBatch) + ? Math.min(issuerMaxBatchSize, requestBatch, 10) : 1🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/openid4vc/holder/credentialBindingResolver.ts` around lines 37 - 43, The batch-size calculation allows numeric requestBatch values to bypass the 10-cap and accept zero/negative/fractional inputs; update the logic that computes batchSize (the variable) to first validate and normalize requestBatch: if requestBatch === true keep Math.min(issuerMaxBatchSize, 10), if typeof requestBatch === 'number' coerce to an integer via Math.floor, clamp it into the valid range Math.max(1, Math.min(issuerMaxBatchSize, 10, normalizedRequestBatch)), otherwise default to 1; ensure you reference requestBatch, issuerMaxBatchSize and batchSize when making this change so downstream code that generates keys uses a safe positive integer.src/cliAgent.ts-278-290 (1)
278-290:⚠️ Potential issue | 🟠 MajorRemove the certificate-verification debug logs.
This trust callback currently writes
tenantIdand auth mode to stdout on every X.509 verification. In a multi-tenant deployment that's sensitive operational metadata, and theseconsole.logcalls bypass the structured logger/redaction path.💡 Proposed fix
//TODO: We need to trust the certificate tenant wise, for that we need to fetch those details from platform const tenantId = agentContext.contextCorrelationId - console.log('[getTrustedCertificatesForVerification] tenantId from agentContext:', tenantId) const authType = getAuthType() - console.log('[getTrustedCertificatesForVerification] authType:', authType) if (authType === AuthTypes.ClientAuth) { return await getX509CertsByClientToken(tenantId, certificateChain) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/cliAgent.ts` around lines 278 - 290, Remove the two debug console.log statements that leak tenantId and authType during X.509 verification: eliminate the lines logging agentContext.contextCorrelationId and getAuthType() inside the trust callback (the block that checks getAuthType() === AuthTypes.ClientAuth). Instead, if structured auditing is required use the existing structured logger with redaction elsewhere; keep the conditional flow that calls getX509CertsByClientToken(tenantId, certificateChain) or getX509CertsByUrl() unchanged (references: agentContext.contextCorrelationId, getAuthType(), AuthTypes.ClientAuth, getX509CertsByClientToken, getX509CertsByUrl).src/cliAgent.ts-248-267 (1)
248-267:⚠️ Potential issue | 🟠 Major
NODE_ENV === 'PROD'will fail on standard production deployments.Most Node.js deployments set
NODE_ENV=production(lowercase), notPROD. When using the standard convention, these OID4VC base URLs fall back toAGENT_HTTP_URL, causing issuer/verifier metadata to advertise the wrong external address in production.Proposed fix
- process.env.NODE_ENV === 'PROD' + ['production', 'prod'].includes((process.env.NODE_ENV ?? '').toLowerCase()) ? `https://${requireEnv('APP_URL')}/oid4vci` : `${requireEnv('AGENT_HTTP_URL')}/oid4vci`, ... - process.env.NODE_ENV === 'PROD' + ['production', 'prod'].includes((process.env.NODE_ENV ?? '').toLowerCase()) ? `https://${requireEnv('APP_URL')}/oid4vp` : `${requireEnv('AGENT_HTTP_URL')}/oid4vp`,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/cliAgent.ts` around lines 248 - 267, The NODE_ENV check in the OpenId4VcModule config (openid4vc -> issuer.baseUrl and verifier.baseUrl) uses 'PROD' which is non-standard; update the condition to detect production correctly (e.g., compare to 'production' or perform a case-insensitive check) so requireEnv('APP_URL') is used in real production deployments instead of falling back to AGENT_HTTP_URL; modify the NODE_ENV checks around issuer and verifier baseUrl to use the corrected comparison while keeping the existing ternary structure and env helpers (requireEnv/AGENT_HTTP_URL) intact.src/controllers/openid4vc/holder/holder.service.ts-120-123 (1)
120-123:⚠️ Potential issue | 🟠 MajorReuse the caller's selected credential configuration ids here.
The authorization step scopes the flow with
credentialsToRequest, but this request asks for everycredential_configuration_idin the offer. Multi-credential offers can therefore over-request or fail after a successful authorization step.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/openid4vc/holder/holder.service.ts` around lines 120 - 123, The call to agentReq.agent.modules.openid4vc.holder.requestCredentials is overriding the caller's requested credentials by always passing resolvedCredentialOffer.credentialOfferPayload.credential_configuration_ids; change this to prefer the caller's selected ids (e.g., options.credentialsToRequest or options.credentialConfigurationIds) and only fall back to resolvedCredentialOffer.credentialOfferPayload.credential_configuration_ids if the caller did not provide them, so requestCredentials uses the same credentials the authorization step scoped.src/controllers/openid4vc/verifiers/verifier.Controller.ts-21-68 (1)
21-68:⚠️ Potential issue | 🟠 MajorWrap verifier-service failures with the shared error mapper.
These handlers return service promises directly instead of normalizing through
ErrorHandlingService.handle. The new verifier endpoints will otherwise leak raw errors or generic 500s instead of the repo's existing HTTP responses.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/openid4vc/verifiers/verifier.Controller.ts` around lines 21 - 68, All controller methods (createVerifier, updateVerifierMetadata, getVerifiersByQuery, getVerifier, deleteVerifier) currently return verifierService promises directly and must be wrapped with the shared ErrorHandlingService.handle to normalize errors; replace each direct call to this.verifierService.* with a call to ErrorHandlingService.handle (or this.errorHandlingService.handle if injected) passing a function that invokes the service (e.g., () => this.verifierService.createVerifier(request, options)) and the request/context so that service failures are mapped into the repo's standard HTTP responses.src/utils/helpers.ts-160-166 (1)
160-166:⚠️ Potential issue | 🟠 MajorRedact tokens and certificate chains from logs.
tokenResponse.datawill typically contain the bearer token, and the later log dumps the full X.509 chain. That turns auth material and certificate subject data into log data.Also applies to: 250-250
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/helpers.ts` around lines 160 - 166, The logs currently print sensitive auth material (tokenResponse.data including access_token and X.509 chains); update the logging around tokenResponse (the console.log calls referencing tokenResponse.status and tokenResponse.data, and the error log that JSON.stringify tokenResponse.data) to avoid printing secrets: log only non-sensitive metadata (e.g., tokenResponse.status and a masked summary) and redact fields like access_token and any certificate chains (replace values with "[REDACTED]" or omit them) before stringifying; apply the same redaction to the other occurrence that logs tokenResponse.data (the later occurrence noted in the review). Ensure the variable names to change are tokenResponse, token, and label, and keep throwing the Error when token is missing.src/controllers/openid4vc/holder/holder.Controller.ts-24-101 (1)
24-101:⚠️ Potential issue | 🟠 MajorNormalize holder-service errors before returning.
Like the verifier controller, these endpoints skip
ErrorHandlingService.handle, so bad offers/proof requests will return inconsistent errors compared with the rest of the API.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/openid4vc/holder/holder.Controller.ts` around lines 24 - 101, The controller methods (e.g., getSdJwtCredentials, getMdocCredentials, decodeMdocCredential, resolveCredOffer, requestAuthorizationForCredential, requestCredential, resolveProofRequest, acceptProofRequest, decodeSdJwt, delete) are directly returning holderService results and bypass ErrorHandlingService.handle; update each method to catch thrown errors from holderService calls and pass them to ErrorHandlingService.handle(request, error) (matching the pattern used in the verifier controller) so responses are normalized; ensure you import ErrorHandlingService if not already and apply the try/catch→handle pattern to every method that calls holderService.src/utils/helpers.ts-139-143 (1)
139-143:⚠️ Potential issue | 🟠 MajorSet explicit timeouts on both trust-service calls.
Both
axios.postcalls use the default infinite timeout. A stuck token or match endpoint can hang the request path and exhaust connections under load.Suggested fix
tokenResponse = await axios.post<any>( tokenUrl, { clientId, clientSecret }, - { headers: { 'Content-Type': 'application/json', accept: 'application/json' } }, + { + timeout: 10000, + headers: { 'Content-Type': 'application/json', accept: 'application/json' }, + }, )const matchResponse = await axios.post<{ matched: boolean }>( matchUrl, { x509, ...(tenantId && { tenantId }) }, - { headers: { 'Content-Type': 'application/json', accept: 'application/json', ...authHeaders } }, + { + timeout: 10000, + headers: { 'Content-Type': 'application/json', accept: 'application/json', ...authHeaders }, + }, )Also applies to: 189-193
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/helpers.ts` around lines 139 - 143, The two axios.post calls (the one assigning tokenResponse and the other later for the match/verify request) currently use the default infinite timeout; update both calls to include an explicit timeout option (e.g., timeout: <ms>) in the axios config object so requests cannot hang -- ideally use a shared constant or env var (e.g., TRUST_SERVICE_TIMEOUT) and merge it into the existing config that includes headers (Content-Type/accept) so both the token request and the match request use the same configurable timeout value.src/controllers/agent/AgentController.ts-23-26 (1)
23-26:⚠️ Potential issue | 🟠 Major
labelnow contains the correlation id, not the label.
contextCorrelationIdis an internal correlation/tenant identifier. Returning it under the existinglabelfield changes the/agentcontract for clients that display or persist the human-readable agent label.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/agent/AgentController.ts` around lines 23 - 26, The response is exposing the internal contextCorrelationId as the public "label" field; change the mapping in AgentController so "label" returns the agent's human-readable name (e.g., use request.agent.label) and do not return request.agent.context.contextCorrelationId as the label; if request.agent.label may be undefined, fall back to a non-sensitive field such as request.agent.context.label or an empty string, and keep request.agent.modules.didcomm.config.endpoints unchanged.src/utils/helpers.ts-77-82 (1)
77-82:⚠️ Potential issue | 🟠 MajorThe validity window is anchored to today's day-of-month.
If this runs on March 27 with
startFromCurrentMonth = false, a "3 year" cert becomes valid from January 27 and expires on January 27 three years later. That backdates the cert and shortens the effective validity by almost three months. Use the first day of the chosen month/year instead.Suggested fix
- const startDay = now.getUTCDate() + const startDay = 1🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/helpers.ts` around lines 77 - 82, The code currently anchors the validity window to today's day-of-month via startDay = now.getUTCDate(), which backdates certificates; change startDay to 1 so the window begins on the first day of the chosen month/year (keep startMonth logic: startFromCurrentMonth ? now.getUTCMonth() : 0) and rebuild notBefore and notAfter using startYear, startMonth, and startDay (first day of month) to ensure full expected validity.src/utils/agent.ts-35-51 (1)
35-51:⚠️ Potential issue | 🟠 Major
endpointsis accepted here but never stored on the agent.After this change, downstream code reads
request.agent.modules.didcomm.config.endpoints, butsetupAgentno longer writes the incomingendpointsinto any agent/module config./agentand invitation creation can therefore return empty/undefined endpoints after initialization.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/agent.ts` around lines 35 - 51, setupAgent currently accepts the endpoints parameter but never writes it to the agent/module config, so request.agent.modules.didcomm.config.endpoints ends up empty; update setupAgent to persist the incoming endpoints (the endpoints array) into the agent initialization config used by the DIDComm module (e.g., add endpoints to the InitConfig or the specific didcomm module config created inside setupAgent) so that request.agent.modules.didcomm.config.endpoints is populated after initialization; ensure you reference the endpoints argument in setupAgent and wire it into the InitConfig/didcomm config used by the agent.src/utils/helpers.ts-100-114 (1)
100-114:⚠️ Potential issue | 🟠 MajorFail fast on unsupported curves.
Silently defaulting an unknown
Curve | KeyAlgorithmtoEC/P-256can generate the wrong key metadata and produce invalid cert/JWK output. Throw here instead of coercing.Suggested fix
} else { - keyTypeInfo = { - kty: 'EC', - crv: 'P-256', - } + throw new Error(`Unsupported curve/key algorithm: ${String(key)}`) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/helpers.ts` around lines 100 - 114, The current fallback silently coerces unknown normalizedCurve to EC/P-256; instead detect unsupported curves and throw a clear error. In the branch handling normalizedCurve/curveToKty (the code that sets keyTypeInfo using kty/crv), replace the final else that assigns {kty: 'EC', crv: 'P-256'} with a thrown Error that includes the received normalizedCurve (and optionally original input) so callers fail fast when curveToKty[normalizedCurve] is not 'OKP' or 'EC'. Keep the OKP and EC branches as-is and ensure the thrown message references normalizedCurve and the function name or context where keyTypeInfo is being set.src/controllers/openid4vc/issuers/issuer.service.ts-29-40 (1)
29-40:⚠️ Potential issue | 🟠 MajorDon't let a missing issuer module look like a successful call.
createIssuerAgentthrows whenopenid4vc.issueris absent, but these methods use optional chaining and can quietly returnundefined/no-op instead. Keep the same explicit guard here so misconfiguration fails fast.Also applies to: 44-45, 53-54
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/openid4vc/issuers/issuer.service.ts` around lines 29 - 40, The getIssuersByQuery method (and the other methods using optional chaining) currently uses optional chaining on agentReq.agent.modules.openid4vc.issuer which can silently return undefined; change it to explicitly assert/throw if the issuer module is missing (same pattern as createIssuerAgent) before calling getIssuerByIssuerId or getAllIssuers so misconfiguration fails fast; update getIssuersByQuery to fetch the issuer module into a local variable (e.g., const issuer = agentReq.agent.modules.openid4vc.issuer) and throw a clear error if !issuer, then call issuer.getIssuerByIssuerId(publicIssuerId) or issuer.getAllIssuers(); apply the same explicit guard to the other methods in this file that currently use optional chaining.src/controllers/openid4vc/issuers/issuer.service.ts-47-50 (1)
47-50:⚠️ Potential issue | 🟠 MajorDelete uses internal record id, inconsistent with other operations.
The
deleteIssuerendpoint expects the internal recordid(documented as "by record id" in line 83 of the controller), whilegetIssuer,updateIssuerMetadata, and other operations use the publicpublicIssuerId. Callers cannot consistently use the same identifier across operations. Either delete should acceptpublicIssuerIdand resolve the internal id, or the controller contract should make the distinction explicit.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/openid4vc/issuers/issuer.service.ts` around lines 47 - 50, deleteIssuer currently deletes by internal record id while other methods use publicIssuerId; change deleteIssuer (in issuer.service.ts) to accept a publicIssuerId, query OpenId4VcIssuerRepository for the record (e.g., using a method like findByPublicIssuerId or getByPublicIssuerId) to obtain the internal id, handle a not-found case by throwing/returning an appropriate error, then call deleteById with the resolved internal id; update the method signature and any controller/docs so callers use publicIssuerId consistently (or alternatively support both by detecting which form was passed and resolving accordingly).src/controllers/x509/x509.service.ts-223-223 (1)
223-223:⚠️ Potential issue | 🟠 MajorSecurity: Avoid logging seed/key material.
Logging the seed exposes sensitive cryptographic material that could be used to derive private keys. This is a security risk, especially in production environments.
🔒 Proposed fix to remove sensitive logging
- agent.config.logger.debug(`createKey: got seed ${seed}`) + agent.config.logger.debug(`createKey: seed generated successfully`)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/x509/x509.service.ts` at line 223, The debug statement in createKey logs the sensitive seed (agent.config.logger.debug(`createKey: got seed ${seed}`)); remove or redact this logging so raw seed/key material is never written to logs—either delete the logger.debug call or replace it with a non-sensitive message (e.g., "createKey: seed received" without the value) and ensure any references to 'seed' or derived key material are not interpolated into logs.src/utils/oid4vc-agent.ts-91-95 (1)
91-95:⚠️ Potential issue | 🟠 MajorReplace the literal issuer placeholder before issuing SD-JWT-DC credentials.
issuer: 'ISSUER_HOST'will be emitted as-is unless another layer rewrites it. That produces credentials with an invalidissvalue and breaks trust checks against your published issuer metadata.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/oid4vc-agent.ts` around lines 91 - 95, The issuer field currently uses the literal placeholder 'ISSUER_HOST' in the issuer object (method: 'x5c', x5c: ...), which must be replaced with the real issuer URL used for issuing SD-JWT-DC credentials; change that property to read the actual issuer value from configuration or the runtime OIDC/issuer metadata (e.g., an existing issuerHost/oidcIssuer/config.issuer variable or process.env) and ensure it is a fully-qualified HTTPS issuer string that matches your published issuer metadata.src/utils/oid4vc-agent.ts-302-316 (1)
302-316:⚠️ Potential issue | 🟠 MajorHarden the trust-list fetch path.
This external call has no timeout, and the response is only checked with
Array.isArraybefore being cast tostring[]. A stalled trust-list endpoint can hang request handling indefinitely, and non-string entries will slip through until certificate parsing fails later.Suggested fix
- const response = await fetch(trustListUrl) + const controller = new AbortController() + const timeout = setTimeout(() => controller.abort(), 10_000) + const response = await fetch(trustListUrl, { signal: controller.signal }).finally(() => clearTimeout(timeout)) @@ - const data = await response.json() + const data: unknown = await response.json() - if (!Array.isArray(data) || data.length === 0) { + if (!Array.isArray(data) || data.length === 0 || !data.every((cert) => typeof cert === 'string')) { throw new Error('[getX509CertsByUrl] trust list is empty or invalid') }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/oid4vc-agent.ts` around lines 302 - 316, The trust-list fetch in getX509CertsByUrl currently has no timeout and casts the parsed JSON to string[] without validating entries; implement an AbortController with a configurable timeout (use a local timeout constant) to abort the fetch to avoid hanging, ensure you check response.ok as now, then parse JSON and validate that data is an array and every element is a non-empty string (e.g., Array.isArray(data) && data.every(item => typeof item === 'string' && item.trim().length>0)), throw descriptive errors if the fetch times out, the response is not ok, the JSON is not an array, or contains non-string/empty entries, keep the logger.info(`[getX509CertsByUrl] fetched certificates count: ${data.length}`) after validation and return the validated string[].src/utils/oid4vc-agent.ts-50-57 (1)
50-57:⚠️ Potential issue | 🟠 MajorUse the configured DID key instead of always taking the first verification method.
If
signerOptions.keyIdpoints to a non-first key in the DID document, this mapper still emitsdidUrl = verificationMethod[0].id. The issued SD-JWT will then advertise the wrong issuer key and fail verification.Suggested fix
- // Set the first verificationMethod as backup, in case we won't find a match - if (didDocument.verificationMethod?.[0].id) { - issuerDidVerificationMethod = didDocument.verificationMethod?.[0].id - } + const verificationMethod = credential.signerOptions.keyId + ? didDocument.verificationMethod?.find((method) => method.id === credential.signerOptions.keyId) + : didDocument.verificationMethod?.[0] + + issuerDidVerificationMethod = verificationMethod?.id🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/oid4vc-agent.ts` around lines 50 - 57, The code in the SignerMethod.Did branch always picks verificationMethod[0].id which breaks cases where credential.signerOptions.keyId points to a different key; update the logic in the block that resolves the DID document (the code that calls agentContext.dependencyManager.resolve(DidsApi) and didsApi.resolveDidDocument) to search didDocument.verificationMethod for an entry whose id or fragment matches credential.signerOptions.keyId and set issuerDidVerificationMethod to that match, falling back to verificationMethod[0].id only if no matching keyId is found; ensure you handle both full DID URL and fragment-only keyId formats when comparing.
🟡 Minor comments (13)
src/controllers/anoncreds/endorser-transaction/EndorserTransactionController.ts-1-203 (1)
1-203:⚠️ Potential issue | 🟡 MinorDelete dead code instead of commenting it out.
The entire controller has been commented out rather than deleted. Evidence confirms this is unused code:
- No test files reference
EndorserTransactionController- No code imports or uses this controller
- The
/anoncreds/transactionsendpoints are not documented inswagger.json(unlike other/anoncreds/endpoints)- No TODO or explanation for the change
This creates maintenance burden with no benefit. Since these endpoints were never added to the public API spec, delete the entire
EndorserTransactionController.tsfile.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/anoncreds/endorser-transaction/EndorserTransactionController.ts` around lines 1 - 203, The file contains a fully commented-out EndorserTransactionController (class EndorserTransactionController and its methods endorserTransaction, didNymTransaction, writeSchemaAndCredDefOnLedger, submitSchemaOnLedger, submitCredDefOnLedger) which is dead code; delete this file entirely and remove any commented imports or unused symbols left in it, and run a quick repo-wide search for EndorserTransactionController (and the endpoint path '/anoncreds/transactions') to confirm there are no live references before committing.samples/sampleWithApp.ts-24-28 (1)
24-28:⚠️ Potential issue | 🟡 MinorUnused variable and malformed response string.
Two issues in this code segment:
config(line 25) is now unused since the response no longer referencesconfig.label- The response string has an errant comma:
"Hello, agent initialized: , ${...}"— the: ,sequence appears to be a copy-paste artifact🔧 Suggested fix
app.post('/greeting', jsonParser, (req, res) => { - const config = agent.dependencyManager.resolve(AgentConfig) - - res.send(`Hello, agent initialized: , ${agent.isInitialized}!`) + res.send(`Hello, agent initialized: ${agent.isInitialized}!`) })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@samples/sampleWithApp.ts` around lines 24 - 28, The handler registered with app.post('/greeting', jsonParser, ...) declares an unused local const config from agent.dependencyManager.resolve(AgentConfig) and returns a malformed string with an extra ",": remove the unused variable or actually use it (e.g., include config.label) and fix the response template so it reads correctly (for example "Hello, agent initialized: ${agent.isInitialized}" or "Hello, agent initialized: ${agent.isInitialized}, label: ${config.label}") while keeping app.post, jsonParser, agent.dependencyManager.resolve(AgentConfig), config, and agent.isInitialized referenced accurately.Dockerfile-14-14 (1)
14-14:⚠️ Potential issue | 🟡 MinorRemoving
--frozen-lockfilemay lead to inconsistent builds.Without
--frozen-lockfile,yarn installmay update the lockfile ifpackage.jsonandyarn.lockdiverge, potentially causing non-reproducible builds in CI/CD pipelines.🔧 Suggested fix
-RUN yarn install --network-timeout 600000 +RUN yarn install --frozen-lockfile --network-timeout 600000🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Dockerfile` at line 14, The Dockerfile's RUN invocation currently uses "yarn install --network-timeout 600000" which allows yarn to modify yarn.lock and can cause non-reproducible builds; restore the lockfile enforcement by using the frozen-lockfile flag (e.g., run the existing RUN yarn install command with --frozen-lockfile) so the build fails if package.json and yarn.lock diverge, ensuring deterministic installs and CI consistency.src/controllers/x509/crypto-util.ts-8-20 (1)
8-20:⚠️ Potential issue | 🟡 MinorRemove or export unused function
pemToRawEcPrivateKey.This function is defined but not exported, making it dead code. Either export it if it's intended for use, or remove it to avoid confusion.
Additionally, there are two issues:
- The function is marked
asyncbut contains noawaitstatements.- Line 17 uses a non-null assertion (
!) onjwk.dwithout validation, unlikepemToRawEd25519PrivateKeywhich properly validates before using.🛠️ If keeping the function, apply these fixes
-async function pemToRawEcPrivateKey(pem: string): Promise<string> { +export function pemToRawEcPrivateKey(pem: string): string { const keyObj: KeyObject = createPrivateKey({ key: pem, format: 'pem', }) - // Extract raw private key (as Buffer) - const rawPrivateKey = keyObj.export({ + const jwk = keyObj.export({ format: 'jwk', - }).d! + }) + if (!jwk.d) throw new Error('Not an EC private key') - return Buffer.from(rawPrivateKey, 'base64').toString('hex') + return Buffer.from(jwk.d, 'base64').toString('hex') }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/x509/crypto-util.ts` around lines 8 - 20, The function pemToRawEcPrivateKey is unused and should be removed or exported; if you keep it, remove the unnecessary async modifier, validate that keyObj.export({format: 'jwk'}).d exists (do not use the non-null assertion) and throw or return a clear error like pemToRawEd25519PrivateKey does, and then export the function (add export keyword) so it's reachable; locate and update the pemToRawEcPrivateKey implementation and mirror the validation/error handling pattern used in pemToRawEd25519PrivateKey.src/controllers/anoncreds/cred-def/CredentialDefinitionController.ts-115-118 (1)
115-118:⚠️ Potential issue | 🟡 MinorFix formatting to comply with Prettier rules.
The error handling improvement is good, but the line formatting violates Prettier rules as flagged by ESLint.
🛠️ Proposed formatting fix
if (registerCredentialDefinitionResult.credentialDefinitionState.state === CredentialEnum.Failed) { - const failureReason = registerCredentialDefinitionResult.credentialDefinitionState?.reason ?? 'Failed to register credential definition on ledger' - throw new InternalServerError(failureReason) + const failureReason = + registerCredentialDefinitionResult.credentialDefinitionState?.reason ?? + 'Failed to register credential definition on ledger' + throw new InternalServerError(failureReason) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/anoncreds/cred-def/CredentialDefinitionController.ts` around lines 115 - 118, The if-block in CredentialDefinitionController that checks registerCredentialDefinitionResult.credentialDefinitionState.state === CredentialEnum.Failed needs to be reformatted to satisfy Prettier: break the long conditional/assignment into properly indented lines, place the const failureReason = registerCredentialDefinitionResult.credentialDefinitionState?.reason ?? 'Failed to register credential definition on ledger' on its own line, and put throw new InternalServerError(failureReason) on the following line so the block follows standard Prettier line length and indentation rules while keeping the same variables and logic (registerCredentialDefinitionResult, credentialDefinitionState, CredentialEnum.Failed, failureReason, InternalServerError).src/controllers/auth/AuthController.ts-26-43 (1)
26-43:⚠️ Potential issue | 🟡 Minor
orgIdpath parameter is unused — either use it or remove it.The
orgIdparameter is extracted from the URL path but never used in the request body or URL construction for the trust service call. This appears to be an oversight.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/auth/AuthController.ts` around lines 26 - 43, The getOrgToken method currently accepts a Path parameter orgId that is never used; either remove the orgId parameter from the method signature or include it in the trust service request (e.g., add orgId to the request body or interpolate it into the trustServiceTokenUrl) so the value is actually sent; update the signature references to orgId and the OrgTokenRequest/OrgTokenResponse usage accordingly (modify getOrgToken and any callers) to keep parameter and payload consistent.src/controllers/openid4vc/issuers/issuer.Controller.ts-7-8 (1)
7-8:⚠️ Potential issue | 🟡 MinorThe POST example shows the update payload.
createIssueris annotated withOpenId4VcUpdateIssuerRecordOptionsExample, so the generated OpenAPI docs will advertise the wrong request body for this endpoint. Please switch this to a create-specific example.Also applies to: 20-22
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/openid4vc/issuers/issuer.Controller.ts` around lines 7 - 8, The POST handler createIssuer is annotated with the update-example constant (OpenId4VcUpdateIssuerRecordOptionsExample), causing OpenAPI to show the wrong request body; replace that import and its usage with the create-specific example (e.g., OpenId4VcCreateIssuerRecordOptionsExample) and update the annotation on the createIssuer method (and the other two occurrences around lines 20-22) so the POST endpoint references the create example instead of the update example.src/controllers/openid4vc/verifier-sessions/verification-sessions.Controller.ts-66-66 (1)
66-66:⚠️ Potential issue | 🟡 MinorInconsistent route parameter syntax.
Lines 66 and 80 use
/:verificationSessionIdsyntax, but TSOA typically uses{verificationSessionId}(as seen inissuance-sessions.Controller.tsat lines 40, 80, 96). This inconsistency could cause routing issues.🐛 Proposed fix to use consistent TSOA syntax
- `@Get`('/:verificationSessionId') + `@Get`('{verificationSessionId}') public async getVerificationSessionsById(- `@Get`('/response/:verificationSessionId') + `@Get`('/response/{verificationSessionId}') public async getVerifiedAuthorizationResponse(Also applies to: 80-80
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/openid4vc/verifier-sessions/verification-sessions.Controller.ts` at line 66, The route parameter syntax in verification-sessions.Controller.ts is inconsistent with TSOA: replace the two occurrences of `@Get`('/:verificationSessionId') with TSOA-style `@Get`('{verificationSessionId}') to match issuance-sessions.Controller.ts; locate the decorators above the methods handling verificationSessionId in the verification sessions controller and update them so the route parameter braces use {verificationSessionId} instead of /:verificationSessionId.src/controllers/x509/x509.service.ts-24-24 (1)
24-24:⚠️ Potential issue | 🟡 MinorClass name should use PascalCase.
The class
x509Servicestarts with lowercase, violating naming conventions. Static analysis also flags this at line 217. Rename toX509Service.♻️ Proposed fix
-class x509Service { +class X509Service {-export const x509ServiceT = new x509Service() +export const x509ServiceT = new X509Service()Also applies to: 217-217
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/x509/x509.service.ts` at line 24, The class currently named x509Service should be renamed to PascalCase X509Service; update the class declaration from x509Service to X509Service and then update all references, instantiations, type annotations, exports/imports, and any static member accesses (search for x509Service and replace with X509Service) so consumers and the default/named export match the new name and static analysis errors disappear; ensure any export statement (e.g., export default or named export) uses X509Service and run the tests/TS compile to catch remaining references.src/controllers/x509/x509.service.ts-226-226 (1)
226-226:⚠️ Potential issue | 🟡 MinorFix typo in error message.
"Unspported" should be "Unsupported".
📝 Proposed fix
- if (!normalizedCurve) throw new Error('Unspported key type for method importKey') + if (!normalizedCurve) throw new Error('Unsupported key type for method importKey')🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/x509/x509.service.ts` at line 226, In the importKey path inside x509.service.ts (where normalizedCurve is checked), fix the typo in the thrown Error message by changing "Unspported key type for method importKey" to "Unsupported key type for method importKey" so the thrown Error from the importKey method (reference: normalizedCurve, importKey) reads correctly.src/controllers/openid4vc/issuance-sessions/issuance-sessions.service.ts-36-36 (1)
36-36:⚠️ Potential issue | 🟡 MinorUse strict equality operator.
Line 36 uses
==(loose equality) instead of===(strict equality). This could lead to unexpected type coercion.🐛 Proposed fix
- if (cred.signerOptions.method == SignerMethod.Did && !cred.signerOptions.did) { + if (cred.signerOptions.method === SignerMethod.Did && !cred.signerOptions.did) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/openid4vc/issuance-sessions/issuance-sessions.service.ts` at line 36, Replace loose equality with strict equality in the conditional that checks the signer method: change the comparison of cred.signerOptions.method to SignerMethod.Did from == to === so it uses strict equality; update the if condition using the symbols cred.signerOptions.method and SignerMethod.Did (inside the issuance sessions logic, e.g., IssuanceSessionsService) to prevent type-coercion issues.src/controllers/openid4vc/verifier-sessions/verification-sessions.service.ts-105-111 (1)
105-111:⚠️ Potential issue | 🟡 MinorMissing not-found error when session doesn't exist.
getVerificationSessionsByIddoesn't throw when the session is not found (unlikegetVerifiedAuthorizationResponseat line 119-121 which does check). This could returnundefinedunexpectedly.🛡️ Proposed fix to add not-found handling
public async getVerificationSessionsById(agentReq: Req, verificationSessionId: string) { const verifier = agentReq.agent.modules.openid4vc.verifier if (!verifier) { throw new Error('OID4VC verifier module not initialized') } - return await verifier.getVerificationSessionById(verificationSessionId) + const session = await verifier.getVerificationSessionById(verificationSessionId) + if (!session) { + throw new Error(`Verification session with id ${verificationSessionId} not found`) + } + return session }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/openid4vc/verifier-sessions/verification-sessions.service.ts` around lines 105 - 111, getVerificationSessionsById currently returns whatever verifier.getVerificationSessionById yields and can return undefined; update it to check the returned value and throw a not-found error when missing (mirror the behavior in getVerifiedAuthorizationResponse). After calling verifier.getVerificationSessionById(verificationSessionId) in getVerificationSessionsById, if the result is falsy, throw a descriptive Error like "Verification session not found" so callers don't receive undefined; reference the verifier module and the getVerificationSessionById call to locate where to add this check.src/controllers/openid4vc/issuance-sessions/issuance-sessions.service.ts-78-84 (1)
78-84:⚠️ Potential issue | 🟡 MinorMissing not-found error handling.
getIssuanceSessionsByIddoesn't validate if the session exists before returning. This could returnundefinedto the caller unexpectedly.🛡️ Proposed fix to add not-found handling
public async getIssuanceSessionsById(agentReq: Req, sessionId: string) { const issuer = agentReq.agent.modules.openid4vc.issuer if (!issuer) { throw new Error('OID4VC issuer module not initialized') } - return issuer.getIssuanceSessionById(sessionId) + const session = await issuer.getIssuanceSessionById(sessionId) + if (!session) { + throw new NotFoundError(`Issuance session with id ${sessionId} not found`) + } + return session }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/controllers/openid4vc/issuance-sessions/issuance-sessions.service.ts` around lines 78 - 84, The getIssuanceSessionsById function currently returns whatever issuer.getIssuanceSessionById(sessionId) yields, which may be undefined; update getIssuanceSessionsById to call issuer.getIssuanceSessionById(sessionId), check the result, and if it's falsy throw a clear not-found error (e.g., throw new Error('Issuance session not found')) instead of returning undefined; keep the existing issuer module initialization check using agentReq.agent.modules.openid4vc.issuer and reference the symbols getIssuanceSessionsById and issuer.getIssuanceSessionById when making the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 726a93e9-5f60-4079-9eb8-c40ae6fdc9c2
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (73)
.env.demo.env.sampleDockerfilepackage.jsonpatches/@credo-ts+anoncreds+0.5.3+001+fix: Extensible model confict in Anoncreds and Did.patchpatches/@credo-ts+core+0.5.15+001+message-type-for-messages.patchpatches/@credo-ts+core+0.5.15+003+added-prettyVc-in-JsonCredential-interface.patchpatches/@credo-ts+core+0.5.15+004+commenting validationPresentation to avoid abandoned issue.patchpatches/@credo-ts+core+0.5.15+005+credential-get-format-data.patchpatches/@credo-ts+core+0.6.0+001+fix: change version string type.patchpatches/@credo-ts+openid4vc+0.6.2.patchpatches/@credo-ts+tenants+0.5.3+001+cache-tenant-record-patch.patchsamples/cliConfig.jsonsamples/sample.tssamples/sampleWithApp.tssrc/authentication.tssrc/cli.tssrc/cliAgent.tssrc/controllers/agent/AgentController.tssrc/controllers/anoncreds/cred-def/CredentialDefinitionController.tssrc/controllers/anoncreds/endorser-transaction/EndorserTransactionController.tssrc/controllers/anoncreds/schema/SchemaController.tssrc/controllers/auth/AuthController.tssrc/controllers/did/DidController.tssrc/controllers/didcomm/basic-messages/BasicMessageController.tssrc/controllers/didcomm/connections/ConnectionController.tssrc/controllers/didcomm/credentials/CredentialController.tssrc/controllers/didcomm/outofband/OutOfBandController.tssrc/controllers/didcomm/proofs/ProofController.tssrc/controllers/didcomm/question-answer/QuestionAnswerController.tssrc/controllers/examples.tssrc/controllers/openid4vc/examples/issuer.examples.tssrc/controllers/openid4vc/holder/credentialBindingResolver.tssrc/controllers/openid4vc/holder/holder.Controller.tssrc/controllers/openid4vc/holder/holder.service.tssrc/controllers/openid4vc/issuance-sessions/issuance-sessions.Controller.tssrc/controllers/openid4vc/issuance-sessions/issuance-sessions.service.tssrc/controllers/openid4vc/issuers/issuer.Controller.tssrc/controllers/openid4vc/issuers/issuer.service.tssrc/controllers/openid4vc/types/holder.types.tssrc/controllers/openid4vc/types/issuer.types.tssrc/controllers/openid4vc/types/verifier.types.tssrc/controllers/openid4vc/verifier-sessions/verification-sessions.Controller.tssrc/controllers/openid4vc/verifier-sessions/verification-sessions.service.tssrc/controllers/openid4vc/verifiers/verifier.Controller.tssrc/controllers/openid4vc/verifiers/verifier.service.tssrc/controllers/polygon/PolygonController.tssrc/controllers/types.tssrc/controllers/x509/crypto-util.tssrc/controllers/x509/x509.Controller.tssrc/controllers/x509/x509.service.tssrc/controllers/x509/x509.types.tssrc/enums/enum.tssrc/errorHandlingService.tssrc/events/BasicMessageEvents.tssrc/events/ConnectionEvents.tssrc/events/CredentialEvents.tssrc/events/ProofEvents.tssrc/events/ReuseConnectionEvents.tssrc/events/WebSocketEvents.tssrc/events/openId4VcIssuanceSessionEvents.tssrc/events/openId4VcVerificationSessionEvents.tssrc/index.tssrc/routes/routes.tssrc/routes/swagger.jsonsrc/server.tssrc/types/request.d.tssrc/utils/agent.tssrc/utils/auth.tssrc/utils/constant.tssrc/utils/helpers.tssrc/utils/oid4vc-agent.tstsoa.json
💤 Files with no reviewable changes (6)
- patches/@credo-ts+core+0.5.15+005+credential-get-format-data.patch
- patches/@credo-ts+tenants+0.5.3+001+cache-tenant-record-patch.patch
- patches/@credo-ts+core+0.5.15+003+added-prettyVc-in-JsonCredential-interface.patch
- patches/@credo-ts+core+0.5.15+001+message-type-for-messages.patch
- patches/@credo-ts+core+0.5.15+004+commenting validationPresentation to avoid abandoned issue.patch
- patches/@credo-ts+anoncreds+0.5.3+001+fix: Extensible model confict in Anoncreds and Did.patch
| if (parsedCertificate) { | ||
| parsedCertificate.publicJwk.keyId = requestSigner.keyId | ||
| } | ||
| options.requestSigner.x5c = [parsedCertificate] |
There was a problem hiding this comment.
Critical: parsedCertificate accessed outside X.509 branch causes runtime error for DID signers.
parsedCertificate is only defined inside the else branch (X.509 mode), but lines 77-80 execute unconditionally. When method === 'did', parsedCertificate is undefined, causing parsedCertificate.publicJwk to throw a TypeError.
🐛 Proposed fix to scope X.509-specific logic correctly
} else {
requestSigner = dto.requestSigner as OpenId4VcIssuerX5cOptions
parsedCertificate = X509Service.parseCertificate(agentReq.agent.context, {
encodedCertificate: requestSigner.x5c[0],
})
requestSigner.issuer = parsedCertificate.sanUriNames[0]
requestSigner.clientIdPrefix = dto.requestSigner.clientIdPrefix ?? ClientIdPrefix.X509Hash
+ parsedCertificate.publicJwk.keyId = requestSigner.keyId
+ requestSigner.x5c = [parsedCertificate]
}
const options: any = {
requestSigner,
verifierId: dto.verifierId,
}
if (dto.responseMode === ResponseModeEnum.DC_API || dto.responseMode === ResponseModeEnum.DC_API_JWT) {
options.expectedOrigins = dto.expectedOrigins
}
if (dto.responseMode) options.responseMode = dto.responseMode
if (dto.presentationExchange) {
// options.presentationExchange = dto.presentationExchange
throw new Error('Presentation Exchange is not supported for now')
}
- if (parsedCertificate) {
- parsedCertificate.publicJwk.keyId = requestSigner.keyId
- }
- options.requestSigner.x5c = [parsedCertificate]
options.dcql = dto.dcql
// }
return (await verifier.createAuthorizationRequest(options)) as any
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/controllers/openid4vc/verifier-sessions/verification-sessions.service.ts`
around lines 77 - 80, The code accesses parsedCertificate and sets
options.requestSigner.x5c unconditionally which fails for DID signers; restrict
the X.509-specific logic by only touching parsedCertificate.publicJwk and
options.requestSigner.x5c when parsedCertificate is defined (i.e., inside the
X.509 branch or guarded by if (parsedCertificate) ), or alternatively check
method === 'x509' before assigning; update the block that sets
requestSigner.keyId and options.requestSigner.x5c so it only runs when
parsedCertificate is present to avoid TypeError for DID signers.
| import { Server } from 'ws' | ||
|
|
||
| export const sendWebSocketEvent = async (server: WebSocket.Server, data: unknown) => { | ||
| export const sendWebSocketEvent = async (server: Server, data: unknown) => { | ||
| server.clients.forEach((client) => { | ||
| if (client.readyState === WebSocket.OPEN) { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check if WebSocket is imported elsewhere or if there's a global polyfill
# Expected: No other imports that would provide WebSocket globally
# Search for WebSocket imports in the codebase
rg -n "import.*WebSocket" --type=ts
# Check if there's a global declaration for WebSocket
rg -n "declare.*WebSocket" --type=tsRepository: credebl/agent-controller
Length of output: 861
🏁 Script executed:
cat -n src/events/WebSocketEvents.tsRepository: credebl/agent-controller
Length of output: 423
🏁 Script executed:
# Check the ws library exports and how it's used in the codebase
rg -A 3 "from 'ws'" src/ --type=ts | head -30Repository: credebl/agent-controller
Length of output: 653
🌐 Web query:
ws npm library WebSocket export OPEN constant
💡 Result:
The 'ws' npm library (Node.js WebSocket implementation) defines WebSocket ready state constants including OPEN in its WebSocket class. These are set as static properties on the WebSocket constructor using Object.defineProperty. Key details: - Ready states array: ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'] (indices 0,1,2,3) - WebSocket.OPEN = 1 (readyStates.indexOf('OPEN')) - Defined in lib/websocket.js - lib/constants.js exists (503B) but primarily exports other constants (e.g., BINARY_TYPES); ready states use the local array. - Usage example: if (client.readyState === WebSocket.OPEN) { client.send(data); } - Official docs confirm: OPEN (1) - The connection is open and ready to communicate. No direct named export of a top-level 'OPEN' constant from the main module; access via imported WebSocket.OPEN after 'import WebSocket from "ws"' or '{ WebSocket } from "ws"'.
Citations:
- 1: https://www.npmjs.com/package/ws
- 2: https://github.com/websockets/ws?tab=readme-ov-file
- 3: https://github.com/websockets/ws/blob/master/doc/ws.md
- 4: https://registry.npmjs.org/ws
- 5: https://github.com/websockets/ws/blob/master/lib/websocket.js?ref=preciselab.io
- 6: https://github.com/websockets/ws
Missing WebSocket import causes runtime error.
Line 5 references WebSocket.OPEN without importing WebSocket. This will fail at runtime with a ReferenceError in all Node.js environments.
🐛 Proposed fix
-import { Server } from 'ws'
+import WebSocket, { Server } from 'ws'
export const sendWebSocketEvent = async (server: Server, data: unknown) => {
server.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { Server } from 'ws' | |
| export const sendWebSocketEvent = async (server: WebSocket.Server, data: unknown) => { | |
| export const sendWebSocketEvent = async (server: Server, data: unknown) => { | |
| server.clients.forEach((client) => { | |
| if (client.readyState === WebSocket.OPEN) { | |
| import WebSocket, { Server } from 'ws' | |
| export const sendWebSocketEvent = async (server: Server, data: unknown) => { | |
| server.clients.forEach((client) => { | |
| if (client.readyState === WebSocket.OPEN) { |
🧰 Tools
🪛 ESLint
[error] 1-1: All imports in the declaration are only used as types. Use import type.
(@typescript-eslint/consistent-type-imports)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/events/WebSocketEvents.ts` around lines 1 - 5, The function
sendWebSocketEvent references WebSocket.OPEN but WebSocket is not imported,
causing a runtime ReferenceError; fix it by adding the WebSocket symbol from the
'ws' package to the top import (e.g., include WebSocket alongside Server in the
import statement) so the check client.readyState === WebSocket.OPEN resolves
correctly.
| httpInbound.app.get( | ||
| '/invitation', | ||
| async (req: { query: { d_m: any; c_i: any }; url: string }, res: { send: (arg0: any) => void }) => { | ||
| if (typeof req.query.d_m === 'string') { | ||
| const invitation = await DidCommConnectionInvitationMessage.fromUrl(req.url.replace('d_m=', 'c_i=')) | ||
| res.send(invitation.toJSON()) | ||
| } | ||
| if (typeof req.query.c_i === 'string') { | ||
| const invitation = await DidCommConnectionInvitationMessage.fromUrl(req.url) | ||
| res.send(invitation.toJSON()) | ||
| } else { | ||
| const { outOfBandInvitation } = await agent.modules.didcomm.oob.createInvitation() | ||
|
|
||
| res.send(outOfBandInvitation.toUrl({ domain: endpoints + '/invitation' })) | ||
| } | ||
| }) | ||
| res.send(outOfBandInvitation.toUrl({ domain: endpoints + '/invitation' })) | ||
| } |
There was a problem hiding this comment.
Fix the /invitation handler's control flow and URL construction.
For ?d_m=..., Line 154 sends a response and then falls into the later else, which sends a second response because the next branch isn't else if. Also, endpoints + '/invitation' stringifies the whole array and produces invalid URLs once multiple endpoints are configured.
Suggested fix
httpInbound.app.get(
'/invitation',
async (req: { query: { d_m: any; c_i: any }; url: string }, res: { send: (arg0: any) => void }) => {
if (typeof req.query.d_m === 'string') {
const invitation = await DidCommConnectionInvitationMessage.fromUrl(req.url.replace('d_m=', 'c_i='))
- res.send(invitation.toJSON())
- }
- if (typeof req.query.c_i === 'string') {
+ return res.send(invitation.toJSON())
+ } else if (typeof req.query.c_i === 'string') {
const invitation = await DidCommConnectionInvitationMessage.fromUrl(req.url)
- res.send(invitation.toJSON())
+ return res.send(invitation.toJSON())
} else {
+ if (endpoints.length === 0) {
+ throw new Error('At least one endpoint is required')
+ }
const { outOfBandInvitation } = await agent.modules.didcomm.oob.createInvitation()
-
- res.send(outOfBandInvitation.toUrl({ domain: endpoints + '/invitation' }))
+ return res.send(outOfBandInvitation.toUrl({ domain: new URL('/invitation', endpoints[0]).toString() }))
}
},
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| httpInbound.app.get( | |
| '/invitation', | |
| async (req: { query: { d_m: any; c_i: any }; url: string }, res: { send: (arg0: any) => void }) => { | |
| if (typeof req.query.d_m === 'string') { | |
| const invitation = await DidCommConnectionInvitationMessage.fromUrl(req.url.replace('d_m=', 'c_i=')) | |
| res.send(invitation.toJSON()) | |
| } | |
| if (typeof req.query.c_i === 'string') { | |
| const invitation = await DidCommConnectionInvitationMessage.fromUrl(req.url) | |
| res.send(invitation.toJSON()) | |
| } else { | |
| const { outOfBandInvitation } = await agent.modules.didcomm.oob.createInvitation() | |
| res.send(outOfBandInvitation.toUrl({ domain: endpoints + '/invitation' })) | |
| } | |
| }) | |
| res.send(outOfBandInvitation.toUrl({ domain: endpoints + '/invitation' })) | |
| } | |
| httpInbound.app.get( | |
| '/invitation', | |
| async (req: { query: { d_m: any; c_i: any }; url: string }, res: { send: (arg0: any) => void }) => { | |
| if (typeof req.query.d_m === 'string') { | |
| const invitation = await DidCommConnectionInvitationMessage.fromUrl(req.url.replace('d_m=', 'c_i=')) | |
| return res.send(invitation.toJSON()) | |
| } else if (typeof req.query.c_i === 'string') { | |
| const invitation = await DidCommConnectionInvitationMessage.fromUrl(req.url) | |
| return res.send(invitation.toJSON()) | |
| } else { | |
| if (endpoints.length === 0) { | |
| throw new Error('At least one endpoint is required') | |
| } | |
| const { outOfBandInvitation } = await agent.modules.didcomm.oob.createInvitation() | |
| return res.send(outOfBandInvitation.toUrl({ domain: new URL('/invitation', endpoints[0]).toString() })) | |
| } | |
| }, | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/utils/agent.ts` around lines 149 - 163, The /invitation handler currently
uses two separate if blocks which can send multiple responses and builds an
invalid domain string from the endpoints array; change the control flow in
httpInbound.app.get to if (typeof req.query.d_m === 'string') { ... } else if
(typeof req.query.c_i === 'string') { ... } else { ... } so only one branch
sends a response, keep using DidCommConnectionInvitationMessage.fromUrl for the
d_m and c_i branches, and when creating the outOfBand invitation call
outOfBandInvitation.toUrl({ domain: Array.isArray(endpoints) ? endpoints[0] :
endpoints }) (or otherwise pick a single endpoint) instead of concatenating the
whole endpoints array.
Signed-off-by: DeepakNemad <deepak.nemade@ayanworks.com>
Signed-off-by: DeepakNemad <deepak.nemade@ayanworks.com>
|




SUMMARY
• Total HIGH/CRITICAL Vulnerabilities: 3
• OS Vulnerabilities: 3 (HIGH: 2, CRITICAL: 1)
• Application Vulnerabilities: 0
REMAINING VULNERABILITIES
FIXED VULNERABILITIES
• axios: Updated to 1.13.5 (CVE-2026-25639)
• flatted: Updated to 3.4.0 (CVE-2026-32141)
• undici: Updated to 6.24.0 (CVE-2026-1526, CVE-2026-1528, CVE-2026-2229)
• All Node.js packages: 0 vulnerabilities detected
REMEDIATION STATUS
• 97% vulnerability reduction achieved
• All application-level vulnerabilities fixed
• Remaining vulnerabilities are OS-level only
SECURITY ENHANCEMENTS IMPLEMENTED
• Non-root user execution (appuser)
• System package updates
• CA certificates installed
• Temporary files cleaned
• Proper file permissions
Summary by CodeRabbit
New Features
Dependency Updates
Improvements