v5.13.4 - Security: ApprovalInbox + APSAdapter fail-closed fixes
The v5.12.2 secret / checkAuth() gate covered only the two mutating routes (POST /approve, POST /deny), leaving GET /, GET /stats, GET /sse, and GET /:id unauthenticated even when a secret was configured, disclosing queu
Security Fixes
GHSA-m4jg-6w3q-gm86 — ApprovalInbox read routes unauthenticated + wildcard CORS (High, CWE-862, CWE-352)
The v5.12.2 secret / checkAuth() gate covered only the two mutating routes (POST /approve, POST /deny), leaving GET /, GET /stats, GET /sse, and GET /:id unauthenticated even when a secret was configured, disclosing queued high-risk action content. The handler also hardcoded Access-Control-Allow-Origin: *.
Fixed:
checkAuth()now gates the entirerouteRequest()pipeline before route dispatch, covering every route uniformly.- Removed the hardcoded wildcard CORS header; added
allowedOrigins?: string[]option onApprovalInboxOptions— no CORS header is sent unless the request Origin exactly matches an allowlisted entry.
Reported by sec-reex via private security advisory.
GHSA-3jf7-33vc-hgf4 — APSAdapter default local verifier accepts any non-empty signature (High, CWE-347, CVSS 8.6)
With the default verificationMode: 'local' and no caller-supplied verifySignature callback (the documented canonical setup), verifyDelegation() treated any non-empty string as a valid cryptographic signature, allowing a forged delegation to obtain a signed SHELL_EXEC permission-grant token with no authentication.
Fixed:
initialize()now throws ifverificationModeislocal(the default) and noverifySignaturecallback is configured.verifyDelegation()'s fallback now returnsfalseinstead of a length check, failing closed as defense in depth.
Also fixed
- SkillSpector Intent-Code Divergence in
scripts/blackboard.pyheader comment (env-scoped data dir I/O documentation).
Testing: 3,388/3,388 tests passing across 38 suites, tsc --noEmit clean.