The alert chat leg resolves its people per organization; an IoT alarm update is quiet on iOS
F12 (IoT close-out, SP14 routing): AlertChatService defaulted to organization 1 and the aliases "sage" / "kamo-monitor", which name nobody in production, so eve...
God eligibility alone passes a right only in the platform org; elsewhere only an open window (IoT R7 round 3)
AuthHelper.hasRight / requireRight let GD (god ELIGIBILITY, no window at all) pass EVERY tenant right in every org (24 controllers: reports, social media, acces...
A closed god-mode window is closed here too (shared SessionPlatformFacts reader)
ViewerPlatformFacts (the ENTER AS SYSTEM USER verdict on support tickets) read GD && godModeActive itself. SecurityService masks an elapsed 30-minute break-glas...
The Canva routes take the right of the screen that calls them, not just a session (SITP TP23)
CanvaController checked only that a member was signed in: anyone in the organization could drive its Canva round trip (create, list, export, import, brand templ...
Webinar booking checks its rights and the type's organisation; an SI brings SIs into its own meetings (SITP TP12)
Owner decision 5 (security gaps fixed with the tools that use them): - /api/webinar: booking (available types, bookable times, a type's sessions, schedule, join...
Adding somebody never opens what was already said to them
POST /sessions/{guid}/members always grew the room in place, so a third person added to a two-person chat could read everything the first two had said. It now r...
Every attachment of stored content records the key it was stored under, via the library
The chat-only StoredContentExtension (299a911) becomes ImageService.storageExtension in the shared library, and the other MediaService paths that attach content...
Meeting-provider OAuth state is an opaque one-time Redis token; refresh is locked and committed on its own
state was base64 JSON {orgId, nonce, provider} built by the caller, the nonce was never stored or checked, and the sessionless callback trusted the decoded orgI...
Deleting a public API key needs MANAGE_ACCESS_RULES, like creating one
Any member of an org could delete the org's public chat / integration keys: deleteKey checked only that the key belonged to the caller's org.
An attachment whose bytes were already stored keeps the extension they were stored under
The content-addressed key is <imgDatId>.<ext>, and every reader builds it from the attaching Img's own fileExt. Dedup matches on the bytes, so the same screensh...
Webinar registrants' leads are indexed, so their calls, texts and emails link to them
PublicWebinarService creates a lead per public webinar registrant through LeadService.createLead, which indexes the lead's phones and addresses (LEAD_CONTACT_PO...
Build each chat snapshot from a graph loaded now, so a lost org-graph event costs one minute, not two (KamoCollab CP02 T17)
The chat policy snapshot is itself a 60 s cache of member facts. Built from OrgGraphCache.get, it could start from a graph already up to 60 s old and keep it fo...
The meeting page link is on the organization's console, chosen by OrgLinkHosts
MeetLinks.meetingPage read the console host off the Kamo Meet join URL: meet.<domain> became internal.<domain>. The join URL names whichever host the room's cre...
A reply may quote only a message in its own conversation
The member chat send resolved the client's parentId with a bare lookup by id and built the reply quote from whatever it found: the parent's text, its author's n...
Trim the mirrored-alias check, and stop it forcing a lazy load per member
Review findings on the AI-full-name fix (4ea53c5): - LOW: the mirrored-username comparison didn't trim either side, so an alias saved with stray whitespace (...
An AI member's chat name is the full name, same as a human's
**************** trusted Member.usernameAlias over the account's own full name whenever the alias was non-blank. MemberCreationService mirrors the account's use...
The missed-message sweep reads the recipient's link hosts before its transaction
SP98-D-9. prepareSend read the recipient organization's domain rows lazily, as a late statement of the sweep's transaction, to choose the letter's console host;...
Chat cards queue boundedly, give up on a hung EmailService in seconds, and never double a mention
SP98-D-7: ChatNoticeDispatcher ran on two threads with an unbounded queue while MemberNotificationClient waited up to 5 s + 30 s (the letter client's chat.email...
A send looks up its AI turn limit and its sender's photo before its transaction opens
SP98-D-5 and D-9. A chat send asked SecurityService for an AI member's charter limit (up to 1 s + 2 s) inside the open send transaction, and read the sender org...
A recording's action item is never due before its meeting
Live (SP14 Task 31, Step 9), a recording made on 2026-09-28 said 'by October second' and the model wrote 'due 2024-10-02' into the summary emailed to the partic...
A stored recording is transcribed, under the id it was saved with
MeetingRecording.id is @GeneratedValue, so save() of the entity whose id ingest had set by hand merged it and the row got an id of its own. The pipeline was han...
The bridge dials the room Meet uses; an AI joins a future meeting at its start; an AI that heard nobody is dialled again
- The dial-in resolver (I1), KM2's roomName and M1's join.roomName name the room Meet uses (the Kamo Meet provider's own room, else the typed name cleaned the...
OAuth return URLs accept both platform consoles; webinar cancel links keep the page that exists
kamouniverse.com is now the platform's primary apex (kamo-shared-library 0e8cf90f): OrgLinkHosts falls back to it, and ROOT_PREFERENCE makes it the platform org...
The viewer's theme host is read before the transaction, never inside it
The Exec2Exec roster, its participant list and every conversation's faces read the viewer's organization's domains lazily, as a late statement of a read-only tr...
An AI invite settles the caller's authority before it looks at the target
invite() answered 409 NOT_AN_ACTIVE_AI_MEMBER before 403 NOT_ALLOWED_TO_INVITE, so a member who could reach M1 but not invite could tell an active AI's member i...
An impersonating admin may not set the member's status text
PUT /api/media/presence/status accepted a sudo session. It is now refused 403: unlike the heartbeat, which nobody chose to send and is ignored quietly, setting ...
A session type without its own gate takes no messages, and a session is described only to its readers
POST **************** authorized CHAT, SUPPORT_TICKET and SOCIAL and then simply ended, so a POST, SYSTEM_BUG or EXEC2EXEC session fell through every gate: any ...
Another org's agent, topic or AI member is a 400 naming the field
The sales agent and support topic checks threw a bare IllegalArgumentException that nothing caught, so saving one the org does not own answered 500. They, and t...
One call per AI per meeting β a dial is claimed before kamoai-service is asked
Two overlapping requests to dial the same AI into the same meeting (a double click, two organizers, a person and the auto-join sweep) could each pass the not-li...
A transcript download answers 409 NOT_READY while the transcript is still being written
M7's errors are M6's plus INVALID_FORMAT (spec 4.4.1). A PENDING or TRANSCRIBING transcript answered 200 with an empty body for vtt and txt; it now answers 409 ...
The roster, participants, history and send survive a database conflict too
Completes 279a389. After it shipped, production logged the same YugabyteDB 40001 "Restart read required" on Exec2Exec's roster (09-27 16:00Z, and three times ea...
A conversation loads and a message sends on the first try
Chat has been failing in two ways a member notices at once: opening a conversation showed "Couldn't load messages" until Retry was pressed, and a sent message s...
The media.* host no longer reaches MediaService's server-to-server endpoints
The media-route IngressRoute sends every path on a media.* host straight to MediaService, past the API gateway, so the gateway's carve-outs (master spec section...
A presenter's recurring meetings block every instance, not just the first
Stream the recording, and run the summary after commit β it ran inside the upload
Jibri's upload read the whole recording into heap (file.getBytes()) on the pod that also serves chat; a two-hour meeting is over a gigabyte. It is now streamed ...
Accept a short-lived otk on the WebSocket handshake, alongside ***
kamo-internal is moving the *** session id out of browser JavaScript: it currently sits in sessionStorage and rides every WebSocket URL as `?***=<128-hex id>`, ...
Pin kamo-shared-library 1.6.1, the only version that exists
The library moved to 1.6.1 and this service still asked for 1.6.0. There is no window in which both resolve: the library is never published to a remote, so the ...
Break a circular bean dependency the STOMP live-session guard introduced
d47b471's SessionAccessGuard field on WebSocketConfig crash-looped every pod: Spring must fully construct WebSocketConfig (a **************** every @Autowired f...
Guard STOMP SUBSCRIBE to a session's live messages and WebRTC signaling
/topic/chat/session/{guid} and /topic/webrtc/session/{guid} were not guarded at all: any authenticated socket could SUBSCRIBE to another session's live chat mes...
Chat attachment uploads authenticate before the body is spooled
POST /sessions/{guid}/attachments bound its parts as a @RequestParam MultipartFile[] method parameter. Spring resolves method parameters before a controller met...
Strip client-supplied identity headers at the media.* edge
media-route (HostRegexp ^media[.].+$) carried only media-websocket-upgrade, so a caller hitting media.<domain> directly could set X-Org-Id, X-Member-Id, X-Publi...
Presence bulk reads and the stale-presence sweep stop using Redis KEYS
getBulkPresence/getBulkLastSeen ran KEYS PRESENCE:*/PRESENCE_LAST_SEEN:* on every call - hit on every presence-socket mount and tab focus - and the 30s sweep ra...
Stop logging STOMP frame headers/payloads and /ws request headers
Two leftover debug-logging spots on the WebSocket path: - WebSocketConfig's inbound channel interceptor logged every STOMP frame at INFO, including accessor....
Imaging proxy forces a download for anything that isn't a safe raster or a stream
GET/HEAD **************** always answered with the client-declared Content-Type from upload, no Content-Disposition, no X-Content-Type-Options and no CSP. ChatA...
The meet-provider OAuth result page can no longer break out of its own script tag
MeetProviderController's GET /oauth/callback is sessionless and reflects the provider's error_description into an inline <script> block. The old jsString() only...
A reply quoting a contact names the contact, not the connection owner
A social contact has no member row, so everything they send is stored under the connection owner's member. The history read already names such a row as the cont...
The SOCIAL read gate refused every social session, not just cross-org ones
Regression in f7b2bd5, live on kamowsmedia. canReadSession (MediaController, copied into SessionFacesController and ChatSessionMembersController) admitted a mem...
WebRTC signaling, webinar management and Canva schedules stop trusting the caller's say-so
Three more of the same shape. - WebRTCSignalingController relayed **************** straight to **************** using only the payload's own sessionGuid, w...
Session reads, ticket mutations and public keys stop trusting the caller's say-so
Four related holes, all the same shape: a request carried an authenticated member, and that was treated as enough. - **************** SessionFacesController.fa...
The public demo page shows no one's contact details, and a site's key books only its own org
Demo requests from the marketing site come from visitors with no account. That path already needed none: the attendee row is the name and email the form collect...
Like what you see shipping?
All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.
