From 962f3219e511e1507b7ab51b25d7f6ed28ac97c2 Mon Sep 17 00:00:00 2001 From: Ty J Everett Date: Tue, 22 Sep 2026 21:06:53 -0700 Subject: [PATCH 1/3] fix(overlay-express): safely serialize GASP failures and record scanner review --- docs/reference/codeql-review-2026-09-23.md | 58 +++++++++++++++++++ docs/reference/package-api-migrations.md | 2 +- governance/package-release-notes.json | 2 +- governance/repository-health/exceptions.json | 14 +++++ .../overlays/overlay-express/CHANGELOG.md | 2 + packages/overlays/overlay-express/README.md | 4 ++ .../overlay-express/src/OverlayExpress.ts | 8 ++- .../src/__tests__/OverlayExpress.test.ts | 43 ++++++++++++++ 8 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 docs/reference/codeql-review-2026-09-23.md diff --git a/docs/reference/codeql-review-2026-09-23.md b/docs/reference/codeql-review-2026-09-23.md new file mode 100644 index 000000000..7394f7e58 --- /dev/null +++ b/docs/reference/codeql-review-2026-09-23.md @@ -0,0 +1,58 @@ +--- +id: codeql-review-2026-09-23 +title: 'CodeQL maintainer review — September 23, 2026' +kind: reference +version: '1.0.0' +last_updated: '2026-09-23' +last_verified: '2026-09-23' +review_cadence_days: 30 +status: stable +tags: [reference, security, codeql, releases] +--- + +# CodeQL maintainer review — September 23, 2026 + +Review baseline: `476b1351baf366cee39f39f610975f7fb1a83e4a`, current default-branch +CodeQL analysis `1822575442`. The full manual CI run +[35813974981](https://github.com/bsv-blockchain/ts-stack/actions/runs/35813974981) +passed all selected workspace, service, platform and mutation lanes. + +Two actual GASP raw-error logging paths (#259/#260) are corrected in source and +covered by public-route regressions using the real error serializer. Those +regressions fail against both original handlers. Their findings must resolve +through a fresh default-branch analysis, not dismissal. + +The following 28 findings have no demonstrated unsafe execution on the reported +path. These are narrowly scoped false-positive dispositions, not waived +vulnerabilities or rule exclusions. Reopen a finding if a caller, validation, +authentication step, filesystem trust assumption, or fixture role changes. The +registry records the maintainer owner, review deadline and removal condition. +All scanners and exact-head merge gates remain enabled. + +| Alerts | Disposition evidence | Source and regression evidence | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [#278](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/278) | The auth middleware server is an un-listened test fixture returned by createServer(app), uses MockWallet and fixed test certificates, and is imported only by tests. It is not a deployed service. The production service rate-limit policies remain enabled. | [packages/middleware/auth-express-middleware/src/__tests/testExpressServer.ts](../../packages/middleware/auth-express-middleware/src/__tests/testExpressServer.ts) | +| [#277](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/277) | The optional peer-target guard validates a supplied target. Both branches then call getAuthenticatedSession and enforce established peer identity and required certificate approval before signing or sending. Omitting the argument selects only the locally initiated implicit destination, not an unauthenticated peer. | [packages/sdk/src/auth/Peer.ts](../../packages/sdk/src/auth/Peer.ts)
[packages/sdk/src/auth/__tests/Peer.messageValidation.security.test.ts](../../packages/sdk/src/auth/__tests/Peer.messageValidation.security.test.ts)
[packages/sdk/src/auth/__tests/Peer.certificatePolicy.test.ts](../../packages/sdk/src/auth/__tests/Peer.certificatePolicy.test.ts) | +| [#276](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/276) | The body-null branch returns 400. The accepted branch still validates method, payload, share and identity hash, then resolveStoreUser verifies authentication and identity binding before ShareService can write. | [infra/wab/src/controllers/ShareController.ts](../../infra/wab/src/controllers/ShareController.ts)
[infra/wab/src/__tests/shareController.test.ts](../../infra/wab/src/__tests/shareController.test.ts) | +| [#275](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/275), [#274](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/274) | Both body guards reject malformed presentation keys and payloads. Accepted input still requires the stored presentation key, completeAuth success for completion, and a user-bound PhoneChangeService authorization; the input guard does not grant account access. | [infra/wab/src/controllers/PhoneChangeController.ts](../../infra/wab/src/controllers/PhoneChangeController.ts)
[infra/wab/src/**tests**/phoneChangeService.test.ts](../../infra/wab/src/__tests__/phoneChangeService.test.ts) | +| [#273](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/273), [#272](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/272) | The body, key and positive-ID guards return 400 for invalid input. The mutation additionally resolves the stored user, checks method.userId against that user, and deletes by both method ID and user ID. | [infra/wab/src/controllers/UserController.ts](../../infra/wab/src/controllers/UserController.ts)
[infra/wab/src/__tests/requestValidation.test.ts](../../infra/wab/src/__tests/requestValidation.test.ts) | +| [#271](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/271), [#269](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/269) | The body guards reject invalid data. startAuth only initiates authentication; completeAuth must return success before registration or a stored presentation key is returned. An accepted JSON shape is not an authentication verdict. | [infra/wab/src/controllers/AuthController.ts](../../infra/wab/src/controllers/AuthController.ts)
[infra/wab/src/__tests/requestValidation.test.ts](../../infra/wab/src/__tests/requestValidation.test.ts) | +| [#270](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/270), [#268](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/268) | The body guards return 400. Completion requires a live deletion session bound to method/config, successful OTP authentication, and atomic consumeAndDeleteUser. The request endpoint deliberately returns the same non-authorizing response for missing accounts. | [infra/wab/src/controllers/AccountDeletionController.ts](../../infra/wab/src/controllers/AccountDeletionController.ts)
[infra/wab/src/__tests/deletionSessionService.test.ts](../../infra/wab/src/__tests/deletionSessionService.test.ts) | +| [#267](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/267), [#266](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/266), [#265](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/265) | The reported conditions reject missing or invalid URL/time fields. Both renewal handlers separately require req.auth identity, a valid public key, a canonical UHRP URL, and owner-bound verified advertisements before constructing and completing a paid renewal. | [infra/uhrp-server-basic/src/routes/renew.ts](../../infra/uhrp-server-basic/src/routes/renew.ts)
[infra/uhrp-server-cloud-bucket/src/routes/renew.ts](../../infra/uhrp-server-cloud-bucket/src/routes/renew.ts)
[infra/uhrp-server-basic/test/renew.security.test.js](../../infra/uhrp-server-basic/test/renew.security.test.js) | +| [#264](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/264) | The reported ENOENT creation branch uses O_CREAT | O_EXCL | O_RDWR with mode 0600. O_EXCL rejects a concurrently created file or symlink rather than following it. The API explicitly requires a trusted owner-only parent directory for subsequent SQLite/journal operations; it does not promise safe use in an adversarial shared directory. | [packages/wallet/wallet-toolbox-examples/src/backup.ts](../../packages/wallet/wallet-toolbox-examples/src/backup.ts)
[packages/wallet/wallet-toolbox-examples/test/backupSafety.test.ts](../../packages/wallet/wallet-toolbox-examples/test/backupSafety.test.ts) | +| [#263](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/263) | The stat/read pair asserts permissions and bytes in a test-owned temporary directory; it is not a production check-then-open authorization decision. | [packages/helpers/simple/src/server/**tests**/json-file-store.security.test.ts](../../packages/helpers/simple/src/server/__tests__/json-file-store.security.test.ts) | +| [#262](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/262), [#261](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/261) | The stat/read pairs inspect generated files in a freshly allocated test-owned directory with fake credentials. They assert permissions and content, not a production access decision. | [infra/uhrp-server-cloud-bucket/src/security/__tests/mkenv.test.js](../../infra/uhrp-server-cloud-bucket/src/security/__tests/mkenv.test.js) | +| [#258](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/258) | The regex extracts generated inline JavaScript for syntax and nonce assertions in a unit test. It is not used to sanitize HTML; adjacent tests exercise hostile configuration and Markdown separately. | [packages/overlays/overlay-express/src/**tests**/makeUserInterface.test.ts](../../packages/overlays/overlay-express/src/__tests__/makeUserInterface.test.ts) | +| [#257](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/257), [#256](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/256), [#255](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/255) | The URL prefixes dispatch canned responses from a mocked global.fetch in unit tests. No network request or host authorization is performed by these branches. | [packages/helpers/simple/src/modules/**tests**/did-wallet-methods.test.ts](../../packages/helpers/simple/src/modules/__tests__/did-wallet-methods.test.ts) | +| [#254](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/254) | contexts is always an array (a single string is wrapped; other values pass denseArray). Array.includes checks exact DID_CONTEXT membership, not a hostname substring. Each element must be a string and this check performs no network fetch. | [packages/helpers/simple/src/core/did-validation.ts](../../packages/helpers/simple/src/core/did-validation.ts) | +| [#253](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/253), [#252](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/252) | The private lookup has one caller in the authenticated admin remove-token handler. assertHash rejects non-string/non-hex txids; assertNonnegativeSafeInteger plus the uint32 bound rejects nonnumeric output indices before lookup. Mongo operator objects cannot reach these value positions. | [packages/overlays/overlay-express/src/OverlayExpress.ts](../../packages/overlays/overlay-express/src/OverlayExpress.ts)
[packages/overlays/overlay-express/src/**tests**/OverlayExpress.test.ts](../../packages/overlays/overlay-express/src/__tests__/OverlayExpress.test.ts) | +| [#251](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/251) | removeBan accepts only the two literal types and sanitize requires a nonempty bounded primitive string. Outpoints receive additional hash/index validation. The reported deleteOne receives scalar values, never operator objects. | [packages/overlays/overlay-express/src/BanService.ts](../../packages/overlays/overlay-express/src/BanService.ts)
[packages/overlays/overlay-express/src/**tests**/BanService.test.ts](../../packages/overlays/overlay-express/src/__tests__/BanService.test.ts) | +| [#250](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/250) | stagedMarker returns null unless uploadId and identifier match anchored separator-free formats. stageObject rejects null before readdir. The directory derives from the configured private DATA_ROOT, not an arbitrary request path. | [infra/uhrp-server-basic/src/chirp/store.ts](../../infra/uhrp-server-basic/src/chirp/store.ts)
[infra/uhrp-server-basic/test/chirpStore.test.js](../../infra/uhrp-server-basic/test/chirpStore.test.js) | +| [#242](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/242) | Writing validated CHIRP session/commit metadata is intended service behavior. writeJSONAtomic fences both destination and UUID-suffixed temporary path under DATA_ROOT, creates privately with wx, and atomically renames. Request-derived metadata content is not an arbitrary executable destination. | [infra/uhrp-server-basic/src/chirp/store.ts](../../infra/uhrp-server-basic/src/chirp/store.ts)
[infra/uhrp-server-basic/test/chirpStore.test.js](../../infra/uhrp-server-basic/test/chirpStore.test.js) | + +OpenSSF Scorecard #225 remains covered by the existing +`scorecard-release-lockfile-refresh` registry entry. Scorecard #204 remains +open: the Best Practices self-assessment is explicitly deferred until the QA +program in #400 is complete, as described in the +[release operations guide](./release-operations.md). Neither is reported as a +fixed CodeQL vulnerability or evidence that the entire QA program is complete. diff --git a/docs/reference/package-api-migrations.md b/docs/reference/package-api-migrations.md index 48fa0dad9..b6a7ef907 100644 --- a/docs/reference/package-api-migrations.md +++ b/docs/reference/package-api-migrations.md @@ -304,7 +304,7 @@ CLI entry points: `{"lch":"./dist/cli.js"}`. - Package documentation: [docs/packages/overlays/overlay-express.md](../packages/overlays/overlay-express.md) - Source: [packages/overlays/overlay-express](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/overlay-express) -- Release note: Adds direct constructor configuration and hardens public overlay services with DNS-pinned public-HTTPS outbound requests, no redirects, finite deadlines and body limits, canonical reorganization checks, bounded health, search, and monitor routes, sanitized no-store administration pages, and token-gated ARC callbacks. +- Release note: Adds direct constructor configuration and hardens public overlay services with DNS-pinned public-HTTPS outbound requests, no redirects, finite deadlines and body limits, canonical reorganization checks, bounded health, search, and monitor routes, sanitized no-store administration pages, and token-gated ARC callbacks. Serializes GASP request failures into one escaped field through the configured logger, including errors containing line separators or throwing serialization hooks. - Migration: Set an ARC callback token of at least 32 bytes before enabling the ARC ingestion route and update the sender to present it. Private-network or plaintext outbound destinations require the explicit allowPrivateHosts development policy; production endpoints must use public HTTPS. Detailed health data is opt-in. Existing canonical public overlay requests and default credential-free CORS remain supported, but operators must roll out callback credentials and egress policy together across every replica. | Public subpath | Runtime target(s) | Declaration target(s) | diff --git a/governance/package-release-notes.json b/governance/package-release-notes.json index 008f8a32a..bd3bf814b 100644 --- a/governance/package-release-notes.json +++ b/governance/package-release-notes.json @@ -140,7 +140,7 @@ "name": "@bsv/overlay-express", "publishedVersion": "2.6.1", "releaseType": "minor", - "summary": "Adds direct constructor configuration and hardens public overlay services with DNS-pinned public-HTTPS outbound requests, no redirects, finite deadlines and body limits, canonical reorganization checks, bounded health, search, and monitor routes, sanitized no-store administration pages, and token-gated ARC callbacks.", + "summary": "Adds direct constructor configuration and hardens public overlay services with DNS-pinned public-HTTPS outbound requests, no redirects, finite deadlines and body limits, canonical reorganization checks, bounded health, search, and monitor routes, sanitized no-store administration pages, and token-gated ARC callbacks. Serializes GASP request failures into one escaped field through the configured logger, including errors containing line separators or throwing serialization hooks.", "migration": "Set an ARC callback token of at least 32 bytes before enabling the ARC ingestion route and update the sender to present it. Private-network or plaintext outbound destinations require the explicit allowPrivateHosts development policy; production endpoints must use public HTTPS. Detailed health data is opt-in. Existing canonical public overlay requests and default credential-free CORS remain supported, but operators must roll out callback credentials and egress policy together across every replica." }, { diff --git a/governance/repository-health/exceptions.json b/governance/repository-health/exceptions.json index 716ae2269..4d7f28502 100644 --- a/governance/repository-health/exceptions.json +++ b/governance/repository-health/exceptions.json @@ -348,6 +348,20 @@ "created": "2026-07-28", "reviewBy": "2026-10-26", "removeWhen": "Remove when the analyzer exempts exhaustive protocol dispatch or a separately reviewed generated opcode table improves auditability and passes every script vector, differential, mutation, fuzz, transaction, browser, and packed-consumer check." + }, + { + "id": "codeql-reviewed-validation-and-test-fixtures-20260923", + "category": "quality-rule", + "target": "Existing CodeQL alerts #242, #250-258 and #261-278, individually reviewed on main 476b1351baf366cee39f39f610975f7fb1a83e4a", + "owner": "ts-stack-maintainers", + "reason": "The exact reported paths are existing primitive validation/authentication guards, contained metadata writes, exclusive file creation, exact array membership, or isolated test assertions. No security bypass is established. Rewriting safe behavior or removing meaningful tests solely to alter heuristic matches would weaken compatibility or assurance; no production control is waived. Detailed per-alert evidence and trust assumptions are retained for review.", + "evidence": [ + "docs/reference/codeql-review-2026-09-23.md", + "https://github.com/bsv-blockchain/ts-stack/actions/runs/35813974981" + ], + "created": "2026-09-23", + "reviewBy": "2026-10-23", + "removeWhen": "Remove when improved CodeQL modeling no longer reports these paths. Reopen affected alerts immediately if their documented guards, callers, filesystem trust assumptions or test-only roles change; any genuine unsafe path requires remediation before release." } ] } diff --git a/packages/overlays/overlay-express/CHANGELOG.md b/packages/overlays/overlay-express/CHANGELOG.md index 09c7f8a5e..07aefa1ff 100644 --- a/packages/overlays/overlay-express/CHANGELOG.md +++ b/packages/overlays/overlay-express/CHANGELOG.md @@ -13,6 +13,8 @@ All notable changes to this project will be documented in this file. The format ### 2.7.2 candidate — outbound and deployment hardening +- Serialize GASP route errors through the configured logger as one escaped field; HTTP error responses, public APIs and wire behavior are unchanged. + - Updates the packed workspace dependency candidate for the additive overlay persistence contract. Runtime behavior and defaults are unchanged; no consumer migration is required. - Validated BASM heights, hashes and txid sets while retaining numeric-string heights, public CORS, topic-free raw transactions, configured limits and sync diff --git a/packages/overlays/overlay-express/README.md b/packages/overlays/overlay-express/README.md index bce6d629d..c1f9ddcf5 100644 --- a/packages/overlays/overlay-express/README.md +++ b/packages/overlays/overlay-express/README.md @@ -50,6 +50,10 @@ hash. Existing Chaintracks/provider adapters remain header-only; they do not claim this stronger position evidence. See the core engine's [BASM validation and recovery limits](../overlay/README.md#basm-peer-validation-and-current-recovery-limits). +GASP route failures use the configured logger and serialize thrown values into a +single escaped field, preserving diagnostic context without allowing request +content to forge additional log records. HTTP error responses remain unchanged. + ## Example Usage Here's a quick example: diff --git a/packages/overlays/overlay-express/src/OverlayExpress.ts b/packages/overlays/overlay-express/src/OverlayExpress.ts index a9de0288c..af626022c 100644 --- a/packages/overlays/overlay-express/src/OverlayExpress.ts +++ b/packages/overlays/overlay-express/src/OverlayExpress.ts @@ -2820,7 +2820,9 @@ export default class OverlayExpress { const response = await engine.provideForeignSyncResponse(req.body, topic) return res.status(200).json(response) } catch (error) { - console.error(chalk.red('Error in /requestSyncResponse:'), error) + this.logger.error( + chalk.red(`Error in /requestSyncResponse: error=${serializeErrorForLog(error)}`) + ) return res.status(400).json({ status: 'error', message: publicErrorMessage(error) @@ -2845,7 +2847,9 @@ export default class OverlayExpress { const response = await engine.provideForeignGASPNode(graphID, txid, outputIndex, header) return res.status(200).json(response) } catch (error) { - console.error(chalk.red('Error in /requestForeignGASPNode:'), error) + this.logger.error( + chalk.red(`Error in /requestForeignGASPNode: error=${serializeErrorForLog(error)}`) + ) return res.status(400).json({ status: 'error', message: publicErrorMessage(error) diff --git a/packages/overlays/overlay-express/src/__tests__/OverlayExpress.test.ts b/packages/overlays/overlay-express/src/__tests__/OverlayExpress.test.ts index 5f4a39c29..36a05b536 100644 --- a/packages/overlays/overlay-express/src/__tests__/OverlayExpress.test.ts +++ b/packages/overlays/overlay-express/src/__tests__/OverlayExpress.test.ts @@ -2146,6 +2146,49 @@ describe('OverlayExpress', () => { }) }) + it.each([ + ['/requestSyncResponse', 'provideForeignSyncResponse'], + ['/requestForeignGASPNode', 'provideForeignGASPNode'] + ])('serializes untrusted %s errors through the configured logger', async (route, method) => { + const safeLog = jest.requireActual('@bsv/overlay') + jest.mocked(serializeErrorForLog).mockImplementation(safeLog.serializeErrorForLog) + const logger = { ...console, log: jest.fn(), warn: jest.fn(), error: jest.fn() } + instance.configureLogger(logger) + const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {}) + try { + const { postSpy } = await startAndCaptureRoutes() + for (const thrown of [ + new Error('untrusted\r\nforged\u0085record\u2028separator\u2029'), + { + toJSON: () => { + throw new Error('unserializable request error') + } + } + ]) { + logger.error.mockClear() + mockEngine[method].mockRejectedValueOnce(thrown) + const response = await invokeCapturedRoute(postSpy, route, { + headers: { 'x-bsv-topic': 'tm_test' }, + body: { graphID: 'graph', txid: '01', outputIndex: 0 } + }) + expect(response.status).toHaveBeenCalledWith(400) + expect(response.json).toHaveBeenCalledWith({ + status: 'error', + message: 'Request could not be processed' + }) + expect(logger.error).toHaveBeenCalledTimes(1) + const args = logger.error.mock.calls[0] + expect(args).toHaveLength(1) + expect(args[0]).toContain(`Error in ${route}: error=`) + expect(args[0]).not.toMatch(/[\r\n\u0085\u2028\u2029]/) + expect(args[0]).toContain(safeLog.serializeErrorForLog(thrown)) + expect(consoleError).not.toHaveBeenCalled() + } + } finally { + consoleError.mockRestore() + } + }) + it('executes public discovery, GASP, and bounded BASM routes', async () => { const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {}) const { getSpy, postSpy } = await startAndCaptureRoutes() From 5b95198df56ea05853f57ce28894a6d4056a8204 Mon Sep 17 00:00:00 2001 From: Ty J Everett Date: Tue, 22 Sep 2026 21:10:29 -0700 Subject: [PATCH 2/3] docs(release): recommend the coordinated SDK candidate --- docs/reference/package-api-migrations.md | 4 ++-- governance/package-release-notes.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference/package-api-migrations.md b/docs/reference/package-api-migrations.md index b6a7ef907..2f190dbdc 100644 --- a/docs/reference/package-api-migrations.md +++ b/docs/reference/package-api-migrations.md @@ -29,7 +29,7 @@ and clean-consumer tests remain the executable type authority. | `@bsv/air-gap` | `0.1.2` | `0.1.3` | patch | [API and usage](../packages/helpers/air-gap.md) | No migration is required for valid BRC-141 v1 senders or decoders. Malformed, oversized, duplicate-heavy, or adversarial high-degree sessions now fail closed or are evicted within the documented limits instead of consuming unbounded resources. | | `@bsv/amountinator` | `2.1.5` | `2.1.6` | patch | [API and usage](../packages/helpers/amountinator.md) | Valid finite inputs retain the public API. Currency identifiers are trimmed and normalized to uppercase; callers that passed non-finite values, empty currencies, coercive options, invalid decimal precision, or non-finite converter results must normalize or reject them before calling because those values now fail closed. | | `@bsv/auth` | `0.1.1` | `0.1.5` | patch | [API and usage](../packages/middleware/auth.md) | No valid proof bytes or public API shape changes. Client and server must use the same protocol tuple; security levels 0, 1, and 2 remain supported and select wallet consent policy while the explicit counterparty scopes derivation at every level. Proof and wallet adapters must supply plain own data fields and dense byte arrays; inherited, accessor-backed, sparse, or malformed runtime shapes fail closed. Structured bodies containing non-finite numbers or negative zero must be normalized to an unambiguous wire representation before signing. | -| `@bsv/auth-express-middleware` | `2.2.3` | `2.2.5` | patch | [API and usage](../packages/middleware/auth-express-middleware.md) | No valid BRC-103/104 wire bytes are changed. Upgrade to @bsv/auth-express-middleware 2.2.5 with @bsv/sdk 2.7.1 or later. When onCertificatesReceived is configured, the callback must call its approval function before returning; replicated deployments must inject a shared CertificateApprovalStore as well as shared session state. Parsed URL-encoded objects are limited to flat string fields, and unsupported nonempty parsed bodies now fail closed. BRC-104 v0.1 does not sign Host/authority, cookies, forwarding metadata, arbitrary standard request headers, or arbitrary standard response headers; pin authority at a trusted edge and do not authorize from omitted metadata. | +| `@bsv/auth-express-middleware` | `2.2.3` | `2.2.5` | patch | [API and usage](../packages/middleware/auth-express-middleware.md) | No valid BRC-103/104 wire bytes are changed. Upgrade to @bsv/auth-express-middleware 2.2.5 with the coordinated @bsv/sdk 2.8.0 release or later. When onCertificatesReceived is configured, the callback must call its approval function before returning; replicated deployments must inject a shared CertificateApprovalStore as well as shared session state. Parsed URL-encoded objects are limited to flat string fields, and unsupported nonempty parsed bodies now fail closed. BRC-104 v0.1 does not sign Host/authority, cookies, forwarding metadata, arbitrary standard request headers, or arbitrary standard response headers; pin authority at a trusted edge and do not authorize from omitted metadata. | | `@bsv/authsocket` | `2.1.1` | `2.1.8` | patch | [API and usage](../packages/messaging/authsocket.md) | No API or wire migration is required for valid JSON events. Existing numeric-key objects under byte-like names are unchanged; typed payment protocols recover historical byte objects at their explicit fields. Outbound non-JSON or ambiguous runtime values, including negative zero, nested undefined, sparse arrays, accessors, hidden/extra properties, and serialization hooks, now fail closed before signing. requestedCertificates is an SDK allowlist, not an application authorization verdict. Distributors must retain THIRD_PARTY_NOTICES.md and LICENSES/ with the package. | | `@bsv/authsocket-client` | `2.1.1` | `2.1.7` | patch | [API and usage](../packages/messaging/authsocket-client.md) | No API or wire migration is required for valid JSON events. Existing numeric-key objects under byte-like names are unchanged; typed payment protocols recover historical byte objects at their explicit fields. Outbound non-JSON or ambiguous runtime values, including negative zero, nested undefined, sparse arrays, accessors, hidden/extra properties, and serialization hooks, now fail closed before signing. The connect event/connected property report Socket.IO transport state, not completed BRC-103 authentication; wait for verified application traffic when local behavior requires a known unpinned server. Distributors who copy the UMD file must keep THIRD_PARTY_NOTICES.md and LICENSES/ with it. | | `@bsv/btms` | `1.1.1` | `1.2.3` | minor | [API and usage](../packages/wallet/btms.md) | Existing local, mainnet, testnet, and number-array behavior is unchanged. TTN consumers select networkPreset teratestnet; all consumers should upgrade to @bsv/sdk 2.4.1 or later for byte-boundary compatibility. Valid canonical token amounts remain compatible. Audit historical tokens for signed, exponent, leading-zero, non-positive, or greater-than-9007199254740991 amount fields before rebuilding wallet state; public number-based operations now fail closed when an aggregate cannot be represented exactly. | @@ -118,7 +118,7 @@ explicitly authorized operations. - Package documentation: [docs/packages/middleware/auth-express-middleware.md](../packages/middleware/auth-express-middleware.md) - Source: [packages/middleware/auth-express-middleware](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/auth-express-middleware) - Release note: Requires the SDK release that binds authenticated BRC-104 request identity to the nonce-selected session; retains application certificate approval against that exact session; canonicalizes parsed request bodies; rejects partial, duplicate, malformed, and unsupported signed input; bounds handshake and response work; contains optional diagnostics; preserves Express sendFile controls; and signs responses emitted through standard Express and Node response methods. -- Migration: No valid BRC-103/104 wire bytes are changed. Upgrade to @bsv/auth-express-middleware 2.2.5 with @bsv/sdk 2.7.1 or later. When onCertificatesReceived is configured, the callback must call its approval function before returning; replicated deployments must inject a shared CertificateApprovalStore as well as shared session state. Parsed URL-encoded objects are limited to flat string fields, and unsupported nonempty parsed bodies now fail closed. BRC-104 v0.1 does not sign Host/authority, cookies, forwarding metadata, arbitrary standard request headers, or arbitrary standard response headers; pin authority at a trusted edge and do not authorize from omitted metadata. +- Migration: No valid BRC-103/104 wire bytes are changed. Upgrade to @bsv/auth-express-middleware 2.2.5 with the coordinated @bsv/sdk 2.8.0 release or later. When onCertificatesReceived is configured, the callback must call its approval function before returning; replicated deployments must inject a shared CertificateApprovalStore as well as shared session state. Parsed URL-encoded objects are limited to flat string fields, and unsupported nonempty parsed bodies now fail closed. BRC-104 v0.1 does not sign Host/authority, cookies, forwarding metadata, arbitrary standard request headers, or arbitrary standard response headers; pin authority at a trusted edge and do not authorize from omitted metadata. | Public subpath | Runtime target(s) | Declaration target(s) | | ---------------- | ------------------------------------ | ---------------------------------------- | diff --git a/governance/package-release-notes.json b/governance/package-release-notes.json index bd3bf814b..a0b9f3a49 100644 --- a/governance/package-release-notes.json +++ b/governance/package-release-notes.json @@ -36,7 +36,7 @@ "publishedVersion": "2.2.3", "releaseType": "patch", "summary": "Requires the SDK release that binds authenticated BRC-104 request identity to the nonce-selected session; retains application certificate approval against that exact session; canonicalizes parsed request bodies; rejects partial, duplicate, malformed, and unsupported signed input; bounds handshake and response work; contains optional diagnostics; preserves Express sendFile controls; and signs responses emitted through standard Express and Node response methods.", - "migration": "No valid BRC-103/104 wire bytes are changed. Upgrade to @bsv/auth-express-middleware 2.2.5 with @bsv/sdk 2.7.1 or later. When onCertificatesReceived is configured, the callback must call its approval function before returning; replicated deployments must inject a shared CertificateApprovalStore as well as shared session state. Parsed URL-encoded objects are limited to flat string fields, and unsupported nonempty parsed bodies now fail closed. BRC-104 v0.1 does not sign Host/authority, cookies, forwarding metadata, arbitrary standard request headers, or arbitrary standard response headers; pin authority at a trusted edge and do not authorize from omitted metadata." + "migration": "No valid BRC-103/104 wire bytes are changed. Upgrade to @bsv/auth-express-middleware 2.2.5 with the coordinated @bsv/sdk 2.8.0 release or later. When onCertificatesReceived is configured, the callback must call its approval function before returning; replicated deployments must inject a shared CertificateApprovalStore as well as shared session state. Parsed URL-encoded objects are limited to flat string fields, and unsupported nonempty parsed bodies now fail closed. BRC-104 v0.1 does not sign Host/authority, cookies, forwarding metadata, arbitrary standard request headers, or arbitrary standard response headers; pin authority at a trusted edge and do not authorize from omitted metadata." }, { "name": "@bsv/authsocket", From d0d4aece9d76ebbe8af3c47bd705ede4f6fb1b13 Mon Sep 17 00:00:00 2001 From: Ty J Everett Date: Tue, 22 Sep 2026 21:15:16 -0700 Subject: [PATCH 3/3] docs(security): link review evidence to immutable source --- docs/reference/codeql-review-2026-09-23.md | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/reference/codeql-review-2026-09-23.md b/docs/reference/codeql-review-2026-09-23.md index 7394f7e58..bbaa069a6 100644 --- a/docs/reference/codeql-review-2026-09-23.md +++ b/docs/reference/codeql-review-2026-09-23.md @@ -31,24 +31,24 @@ All scanners and exact-head merge gates remain enabled. | Alerts | Disposition evidence | Source and regression evidence | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [#278](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/278) | The auth middleware server is an un-listened test fixture returned by createServer(app), uses MockWallet and fixed test certificates, and is imported only by tests. It is not a deployed service. The production service rate-limit policies remain enabled. | [packages/middleware/auth-express-middleware/src/__tests/testExpressServer.ts](../../packages/middleware/auth-express-middleware/src/__tests/testExpressServer.ts) | -| [#277](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/277) | The optional peer-target guard validates a supplied target. Both branches then call getAuthenticatedSession and enforce established peer identity and required certificate approval before signing or sending. Omitting the argument selects only the locally initiated implicit destination, not an unauthenticated peer. | [packages/sdk/src/auth/Peer.ts](../../packages/sdk/src/auth/Peer.ts)
[packages/sdk/src/auth/__tests/Peer.messageValidation.security.test.ts](../../packages/sdk/src/auth/__tests/Peer.messageValidation.security.test.ts)
[packages/sdk/src/auth/__tests/Peer.certificatePolicy.test.ts](../../packages/sdk/src/auth/__tests/Peer.certificatePolicy.test.ts) | -| [#276](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/276) | The body-null branch returns 400. The accepted branch still validates method, payload, share and identity hash, then resolveStoreUser verifies authentication and identity binding before ShareService can write. | [infra/wab/src/controllers/ShareController.ts](../../infra/wab/src/controllers/ShareController.ts)
[infra/wab/src/__tests/shareController.test.ts](../../infra/wab/src/__tests/shareController.test.ts) | -| [#275](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/275), [#274](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/274) | Both body guards reject malformed presentation keys and payloads. Accepted input still requires the stored presentation key, completeAuth success for completion, and a user-bound PhoneChangeService authorization; the input guard does not grant account access. | [infra/wab/src/controllers/PhoneChangeController.ts](../../infra/wab/src/controllers/PhoneChangeController.ts)
[infra/wab/src/**tests**/phoneChangeService.test.ts](../../infra/wab/src/__tests__/phoneChangeService.test.ts) | -| [#273](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/273), [#272](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/272) | The body, key and positive-ID guards return 400 for invalid input. The mutation additionally resolves the stored user, checks method.userId against that user, and deletes by both method ID and user ID. | [infra/wab/src/controllers/UserController.ts](../../infra/wab/src/controllers/UserController.ts)
[infra/wab/src/__tests/requestValidation.test.ts](../../infra/wab/src/__tests/requestValidation.test.ts) | -| [#271](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/271), [#269](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/269) | The body guards reject invalid data. startAuth only initiates authentication; completeAuth must return success before registration or a stored presentation key is returned. An accepted JSON shape is not an authentication verdict. | [infra/wab/src/controllers/AuthController.ts](../../infra/wab/src/controllers/AuthController.ts)
[infra/wab/src/__tests/requestValidation.test.ts](../../infra/wab/src/__tests/requestValidation.test.ts) | -| [#270](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/270), [#268](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/268) | The body guards return 400. Completion requires a live deletion session bound to method/config, successful OTP authentication, and atomic consumeAndDeleteUser. The request endpoint deliberately returns the same non-authorizing response for missing accounts. | [infra/wab/src/controllers/AccountDeletionController.ts](../../infra/wab/src/controllers/AccountDeletionController.ts)
[infra/wab/src/__tests/deletionSessionService.test.ts](../../infra/wab/src/__tests/deletionSessionService.test.ts) | -| [#267](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/267), [#266](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/266), [#265](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/265) | The reported conditions reject missing or invalid URL/time fields. Both renewal handlers separately require req.auth identity, a valid public key, a canonical UHRP URL, and owner-bound verified advertisements before constructing and completing a paid renewal. | [infra/uhrp-server-basic/src/routes/renew.ts](../../infra/uhrp-server-basic/src/routes/renew.ts)
[infra/uhrp-server-cloud-bucket/src/routes/renew.ts](../../infra/uhrp-server-cloud-bucket/src/routes/renew.ts)
[infra/uhrp-server-basic/test/renew.security.test.js](../../infra/uhrp-server-basic/test/renew.security.test.js) | -| [#264](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/264) | The reported ENOENT creation branch uses O_CREAT | O_EXCL | O_RDWR with mode 0600. O_EXCL rejects a concurrently created file or symlink rather than following it. The API explicitly requires a trusted owner-only parent directory for subsequent SQLite/journal operations; it does not promise safe use in an adversarial shared directory. | [packages/wallet/wallet-toolbox-examples/src/backup.ts](../../packages/wallet/wallet-toolbox-examples/src/backup.ts)
[packages/wallet/wallet-toolbox-examples/test/backupSafety.test.ts](../../packages/wallet/wallet-toolbox-examples/test/backupSafety.test.ts) | -| [#263](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/263) | The stat/read pair asserts permissions and bytes in a test-owned temporary directory; it is not a production check-then-open authorization decision. | [packages/helpers/simple/src/server/**tests**/json-file-store.security.test.ts](../../packages/helpers/simple/src/server/__tests__/json-file-store.security.test.ts) | -| [#262](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/262), [#261](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/261) | The stat/read pairs inspect generated files in a freshly allocated test-owned directory with fake credentials. They assert permissions and content, not a production access decision. | [infra/uhrp-server-cloud-bucket/src/security/__tests/mkenv.test.js](../../infra/uhrp-server-cloud-bucket/src/security/__tests/mkenv.test.js) | -| [#258](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/258) | The regex extracts generated inline JavaScript for syntax and nonce assertions in a unit test. It is not used to sanitize HTML; adjacent tests exercise hostile configuration and Markdown separately. | [packages/overlays/overlay-express/src/**tests**/makeUserInterface.test.ts](../../packages/overlays/overlay-express/src/__tests__/makeUserInterface.test.ts) | -| [#257](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/257), [#256](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/256), [#255](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/255) | The URL prefixes dispatch canned responses from a mocked global.fetch in unit tests. No network request or host authorization is performed by these branches. | [packages/helpers/simple/src/modules/**tests**/did-wallet-methods.test.ts](../../packages/helpers/simple/src/modules/__tests__/did-wallet-methods.test.ts) | -| [#254](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/254) | contexts is always an array (a single string is wrapped; other values pass denseArray). Array.includes checks exact DID_CONTEXT membership, not a hostname substring. Each element must be a string and this check performs no network fetch. | [packages/helpers/simple/src/core/did-validation.ts](../../packages/helpers/simple/src/core/did-validation.ts) | -| [#253](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/253), [#252](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/252) | The private lookup has one caller in the authenticated admin remove-token handler. assertHash rejects non-string/non-hex txids; assertNonnegativeSafeInteger plus the uint32 bound rejects nonnumeric output indices before lookup. Mongo operator objects cannot reach these value positions. | [packages/overlays/overlay-express/src/OverlayExpress.ts](../../packages/overlays/overlay-express/src/OverlayExpress.ts)
[packages/overlays/overlay-express/src/**tests**/OverlayExpress.test.ts](../../packages/overlays/overlay-express/src/__tests__/OverlayExpress.test.ts) | -| [#251](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/251) | removeBan accepts only the two literal types and sanitize requires a nonempty bounded primitive string. Outpoints receive additional hash/index validation. The reported deleteOne receives scalar values, never operator objects. | [packages/overlays/overlay-express/src/BanService.ts](../../packages/overlays/overlay-express/src/BanService.ts)
[packages/overlays/overlay-express/src/**tests**/BanService.test.ts](../../packages/overlays/overlay-express/src/__tests__/BanService.test.ts) | -| [#250](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/250) | stagedMarker returns null unless uploadId and identifier match anchored separator-free formats. stageObject rejects null before readdir. The directory derives from the configured private DATA_ROOT, not an arbitrary request path. | [infra/uhrp-server-basic/src/chirp/store.ts](../../infra/uhrp-server-basic/src/chirp/store.ts)
[infra/uhrp-server-basic/test/chirpStore.test.js](../../infra/uhrp-server-basic/test/chirpStore.test.js) | -| [#242](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/242) | Writing validated CHIRP session/commit metadata is intended service behavior. writeJSONAtomic fences both destination and UUID-suffixed temporary path under DATA_ROOT, creates privately with wx, and atomically renames. Request-derived metadata content is not an arbitrary executable destination. | [infra/uhrp-server-basic/src/chirp/store.ts](../../infra/uhrp-server-basic/src/chirp/store.ts)
[infra/uhrp-server-basic/test/chirpStore.test.js](../../infra/uhrp-server-basic/test/chirpStore.test.js) | +| [#278](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/278) | The auth middleware server is an un-listened test fixture returned by createServer(app), uses MockWallet and fixed test certificates, and is imported only by tests. It is not a deployed service. The production service rate-limit policies remain enabled. | [packages/middleware/auth-express-middleware/src/__tests/testExpressServer.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/middleware/auth-express-middleware/src/__tests/testExpressServer.ts) | +| [#277](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/277) | The optional peer-target guard validates a supplied target. Both branches then call getAuthenticatedSession and enforce established peer identity and required certificate approval before signing or sending. Omitting the argument selects only the locally initiated implicit destination, not an unauthenticated peer. | [packages/sdk/src/auth/Peer.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/sdk/src/auth/Peer.ts)
[packages/sdk/src/auth/__tests/Peer.messageValidation.security.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/sdk/src/auth/__tests/Peer.messageValidation.security.test.ts)
[packages/sdk/src/auth/__tests/Peer.certificatePolicy.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/sdk/src/auth/__tests/Peer.certificatePolicy.test.ts) | +| [#276](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/276) | The body-null branch returns 400. The accepted branch still validates method, payload, share and identity hash, then resolveStoreUser verifies authentication and identity binding before ShareService can write. | [infra/wab/src/controllers/ShareController.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/wab/src/controllers/ShareController.ts)
[infra/wab/src/__tests/shareController.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/wab/src/__tests/shareController.test.ts) | +| [#275](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/275), [#274](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/274) | Both body guards reject malformed presentation keys and payloads. Accepted input still requires the stored presentation key, completeAuth success for completion, and a user-bound PhoneChangeService authorization; the input guard does not grant account access. | [infra/wab/src/controllers/PhoneChangeController.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/wab/src/controllers/PhoneChangeController.ts)
[infra/wab/src/**tests**/phoneChangeService.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/wab/src/__tests__/phoneChangeService.test.ts) | +| [#273](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/273), [#272](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/272) | The body, key and positive-ID guards return 400 for invalid input. The mutation additionally resolves the stored user, checks method.userId against that user, and deletes by both method ID and user ID. | [infra/wab/src/controllers/UserController.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/wab/src/controllers/UserController.ts)
[infra/wab/src/__tests/requestValidation.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/wab/src/__tests/requestValidation.test.ts) | +| [#271](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/271), [#269](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/269) | The body guards reject invalid data. startAuth only initiates authentication; completeAuth must return success before registration or a stored presentation key is returned. An accepted JSON shape is not an authentication verdict. | [infra/wab/src/controllers/AuthController.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/wab/src/controllers/AuthController.ts)
[infra/wab/src/__tests/requestValidation.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/wab/src/__tests/requestValidation.test.ts) | +| [#270](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/270), [#268](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/268) | The body guards return 400. Completion requires a live deletion session bound to method/config, successful OTP authentication, and atomic consumeAndDeleteUser. The request endpoint deliberately returns the same non-authorizing response for missing accounts. | [infra/wab/src/controllers/AccountDeletionController.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/wab/src/controllers/AccountDeletionController.ts)
[infra/wab/src/__tests/deletionSessionService.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/wab/src/__tests/deletionSessionService.test.ts) | +| [#267](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/267), [#266](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/266), [#265](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/265) | The reported conditions reject missing or invalid URL/time fields. Both renewal handlers separately require req.auth identity, a valid public key, a canonical UHRP URL, and owner-bound verified advertisements before constructing and completing a paid renewal. | [infra/uhrp-server-basic/src/routes/renew.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/uhrp-server-basic/src/routes/renew.ts)
[infra/uhrp-server-cloud-bucket/src/routes/renew.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/uhrp-server-cloud-bucket/src/routes/renew.ts)
[infra/uhrp-server-basic/test/renew.security.test.js](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/uhrp-server-basic/test/renew.security.test.js) | +| [#264](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/264) | The reported ENOENT creation branch uses O_CREAT | O_EXCL | O_RDWR with mode 0600. O_EXCL rejects a concurrently created file or symlink rather than following it. The API explicitly requires a trusted owner-only parent directory for subsequent SQLite/journal operations; it does not promise safe use in an adversarial shared directory. | [packages/wallet/wallet-toolbox-examples/src/backup.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/wallet/wallet-toolbox-examples/src/backup.ts)
[packages/wallet/wallet-toolbox-examples/test/backupSafety.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/wallet/wallet-toolbox-examples/test/backupSafety.test.ts) | +| [#263](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/263) | The stat/read pair asserts permissions and bytes in a test-owned temporary directory; it is not a production check-then-open authorization decision. | [packages/helpers/simple/src/server/**tests**/json-file-store.security.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/helpers/simple/src/server/__tests__/json-file-store.security.test.ts) | +| [#262](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/262), [#261](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/261) | The stat/read pairs inspect generated files in a freshly allocated test-owned directory with fake credentials. They assert permissions and content, not a production access decision. | [infra/uhrp-server-cloud-bucket/src/security/__tests/mkenv.test.js](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/uhrp-server-cloud-bucket/src/security/__tests/mkenv.test.js) | +| [#258](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/258) | The regex extracts generated inline JavaScript for syntax and nonce assertions in a unit test. It is not used to sanitize HTML; adjacent tests exercise hostile configuration and Markdown separately. | [packages/overlays/overlay-express/src/**tests**/makeUserInterface.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/overlays/overlay-express/src/__tests__/makeUserInterface.test.ts) | +| [#257](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/257), [#256](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/256), [#255](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/255) | The URL prefixes dispatch canned responses from a mocked global.fetch in unit tests. No network request or host authorization is performed by these branches. | [packages/helpers/simple/src/modules/**tests**/did-wallet-methods.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/helpers/simple/src/modules/__tests__/did-wallet-methods.test.ts) | +| [#254](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/254) | contexts is always an array (a single string is wrapped; other values pass denseArray). Array.includes checks exact DID_CONTEXT membership, not a hostname substring. Each element must be a string and this check performs no network fetch. | [packages/helpers/simple/src/core/did-validation.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/helpers/simple/src/core/did-validation.ts) | +| [#253](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/253), [#252](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/252) | The private lookup has one caller in the authenticated admin remove-token handler. assertHash rejects non-string/non-hex txids; assertNonnegativeSafeInteger plus the uint32 bound rejects nonnumeric output indices before lookup. Mongo operator objects cannot reach these value positions. | [packages/overlays/overlay-express/src/OverlayExpress.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/overlays/overlay-express/src/OverlayExpress.ts)
[packages/overlays/overlay-express/src/**tests**/OverlayExpress.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/overlays/overlay-express/src/__tests__/OverlayExpress.test.ts) | +| [#251](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/251) | removeBan accepts only the two literal types and sanitize requires a nonempty bounded primitive string. Outpoints receive additional hash/index validation. The reported deleteOne receives scalar values, never operator objects. | [packages/overlays/overlay-express/src/BanService.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/overlays/overlay-express/src/BanService.ts)
[packages/overlays/overlay-express/src/**tests**/BanService.test.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/packages/overlays/overlay-express/src/__tests__/BanService.test.ts) | +| [#250](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/250) | stagedMarker returns null unless uploadId and identifier match anchored separator-free formats. stageObject rejects null before readdir. The directory derives from the configured private DATA_ROOT, not an arbitrary request path. | [infra/uhrp-server-basic/src/chirp/store.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/uhrp-server-basic/src/chirp/store.ts)
[infra/uhrp-server-basic/test/chirpStore.test.js](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/uhrp-server-basic/test/chirpStore.test.js) | +| [#242](https://github.com/bsv-blockchain/ts-stack/security/code-scanning/242) | Writing validated CHIRP session/commit metadata is intended service behavior. writeJSONAtomic fences both destination and UUID-suffixed temporary path under DATA_ROOT, creates privately with wx, and atomically renames. Request-derived metadata content is not an arbitrary executable destination. | [infra/uhrp-server-basic/src/chirp/store.ts](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/uhrp-server-basic/src/chirp/store.ts)
[infra/uhrp-server-basic/test/chirpStore.test.js](https://github.com/bsv-blockchain/ts-stack/blob/476b1351baf366cee39f39f610975f7fb1a83e4a/infra/uhrp-server-basic/test/chirpStore.test.js) | OpenSSF Scorecard #225 remains covered by the existing `scorecard-release-lockfile-refresh` registry entry. Scorecard #204 remains