Adding people and member security need their rights
POST /members/create, /create-team-member and /bulk-create, and GET /members/lookup-user, now require MANAGE_MEMBERS or an open god window. They checked only fo...
The platform tab, and three links that showed their own keys
Two bugs, both reported from the running site. THE SETTINGS LINKS SHOWED KEY PATHS The three Hosted Computer sub-links carried key: 'computers' | 'capacity' | ...
Require MANAGE_DOCS_SETTINGS on every doc-settings mutation, not just some
The settings page always sent a member without MANAGE_DOCS_SETTINGS away, but ten mutation endpoints in ImagingSettingsController never asked themselves: canMan...
Scope thumbnail backfill to the caller's org; gate history reads by clearance
Two independent gaps in ImagingController: - /backfill-thumbnails selected candidates platform-wide (no organization predicate at all; the last-resort tier w...
Throttle the anonymous careers talent-alert form
CareersPublicController's POST /{orgRef}/alerts is the one anonymous, unauthenticated endpoint in this service that sends an email on every accepted call, with ...
UpdateDocType now requires the doc type to belong to the document's own org
ImageService.updateDocType loaded the target ImgDocType by UUID alone; requireEditableAndOwned proves the caller may edit the Img, but says nothing about whose ...
Org-scoped counterparts for the thumbnail-backfill candidate queries
DocsService's /backfill-thumbnails admin endpoint selected candidates from **************** (platform-wide, no organization predicate) or, as a last resort, a r...
Count an org's unconfirmed talent-alert rows for the anonymous form's cap
DocsService's public talent-alert subscribe endpoint sends a confirmation email on every accepted call, with no limit on how many not-yet-confirmed rows one org...
An IMAP/SMTP connection test must not be usable as a network probe
POST /api/email/member-imap/test and /{id}/imap/test connected to whatever host and port the caller supplied and returned the raw exception message. Any authent...
Alias, domain and personal-mailbox admin actions need a management right
create/delete on an email alias, **************** on the org's sending domains, and **************** on a personal (self-hosted) mailbox all needed only a sessi...
A member's mailboxes and aliases are only readable inside their own organization
GET **************** took no HttpServletRequest at all — no session, no org check anywhere on the path — and GET **************** checked that the CALLER had a ...
A calendar export or import must be one the caller can actually open
GET /export/calendar/{id} and POST /import/{calendarId} took the calendar's UUID alone — no HttpServletRequest, so no session, no org or member check at all. An...
Gate the API on the app, not only the screen
The settings page and the nav option both check organization.isHostedComputers, and until now that was the whole gate. AppAvailabilityInterceptor never mapped /...
A Hosted Computer is never provisioned automatically
Hosted Computers was reachable by both automatic provisioning paths, and either one would have put it in front of every organization on the platform at once. F...
The three templates that never got committed
service-template.yaml, cloud-init.userdata.yaml and cloud-init.networkdata.yaml. They were written into a second worktree and committed from neither — the earli...
SearchService marks its injection constructor, so the service starts
9809d4b gave SearchService a second constructor (a clock, for tests) and marked neither, so Spring chose neither, looked for a no-argument constructor, and the ...
Every folder of a switched-to mailbox works, and search is rebuilt
Switching mailboxes. The folder sidebar always loaded the member's OWN folder tree, whatever mailbox was open - so a second mailbox showed the primary's folders...
Search that honours its query, and every mail action on the mailbox that is open
Two problems on /messages, fixed in the service. Search did not work. The index path threw a ClassCastException on every hit (Instant -> Timestamp, visible in ...
Shared-mailbox **************** need a management right
**************** on /api/email/shared-mailboxes needed only a session — any authenticated member could create a shared mailbox, delete one, or grant themselves ...
Apply the per-party/issued/trashed checks everywhere byte-adjacent paths need them
**************** applied the issued-document check but not the per-party (ACCOUNT_MEMBER_VAULT/LOAN) or trashed-row checks that /download, /stream and the sibli...
Verify RingCentral webhooks before trusting them
RingCentral's inbound call/SMS webhooks were processed with zero verification: WebhookController routed telephony/message-store events straight into ***********...
An OAuth state token is a server-side record, not a blob the browser hands back
/api/email/oauth/callback and **************** are public and sessionless (the provider redirects the browser here with no Kamo session), so `state` was the onl...
A document share now actually reaches its recipient, and edit is gated
**************** matched an ImgShare by ImgShare.member — the SHARER, who created the row so they can list what THEY shared (getSharesByImage) — instead of ImgS...
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...
Re-check clearance when rendering a binder's document items
BinderItem pins the Img row it was built from at assembly time. BinderRenderer.renderItem handed that Img straight to **************** with no check at all for ...
A From override must be an address the caller may send as
POST /api/email/send took request.getFromAddress() straight into the header From and the SMTP envelope sender **************** -> EmailSmtpService.send, and the...
Cap upload size and concurrent conversions on the unauthenticated pipeline endpoints
POST /convert-vector and WS /ws/pipeline take no auth (see this commit's companion report for why that is not fixed here) and, until now, read a caller's whole ...
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...
Stop trusting any https://api.<anything> as a Docs WOPI host
k8s/Docs-deployment.yaml's aliasgroup1 was 'https://api\..*'. Docs's alias matcher (RegexUtil::getValue, std::regex_match) requires only that the WHOLE candidat...
A media presigned URL was not scoped to the caller's org
GET /api/kb/media/{mediaId}/url looked the row up by uid alone (KbMediaService.getPresignedUrl -> **************** unlike every other media read here (presignAl...
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...
Gate chat attachments, voicemails and call recordings by more than org+clearance
MediaService/telephony store chat attachments (CHAT_ATTACHMENT) and voicemail/call recordings (VM_RECORDING, CALL_RECORDING) at ACCESS_LEVEL 0. Every generic im...
The member card can be reached from the keyboard
The card is portalled to the end of <body>, so in document order it follows the whole page: a member who opened it from a name with Enter or focus and pressed T...
No job overlaps itself, and no HTTP call can hang a worker forever
Quartz here runs 10 in-memory worker threads on one replica. 17 of the 24 jobs had no @DisallowConcurrentExecution, so a run that overran its interval started a...
The lead-intake counters join the ledgers the daemon folds and recounts
The intake endpoints' received / imported counters are now a ledger (securityservice create_lead_intake_ledger.sql, applied 2026-09-22): a trigger on lead_intak...
Intake endpoints show exact received/imported counts from the intake ledger
The Lead Intake settings list showed total_received / total_processed / last_received_at straight off the endpoint row, where they were bumped once per payload ...
Intake endpoint counters come from a ledger and stop losing updates
**************** / total_processed / last_received_at were bumped on the endpoint row itself: once per inbound payload (~5/s during a farm import) and once per ...
Refuse to spawn STDIO for an unlisted config, and refuse to connect an SSE/HTTP one to the cluster network
Defense in depth alongside the AIService commit that closes AiMcpController's missing right checks and STDIO refusal at the source: this service is the one that...
MCP configs need MANAGE_AI_SETTINGS, provider/MCP urls can't reach the cluster, quota policies are enforced
Three independent findings, fixed together because the first two share files and a class. 1. AiMcpController had zero right checks on create/update/delete/test...
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...
Bind every WOPI endpoint to the document its token was minted for
CheckFileInfo was the only WOPI endpoint that both compared the access token's document against the request path and re-checked live access; GetFile, PutFile, P...
The session path searches the caller's own org, never the request body
RagSearchController read orgId/memberId/memberType from the JSON body on every path, including requests authenticated by a *** session rather than X-Internal-Au...
Give the postbuild compression probe more time to start the server.
Docker builds can still be settling after prerender workers finish; extend upstream and probe waits and surface child stderr when startup fails.
Lower the floating logo by 3px.
Reduce NAV_LOGO_RISE from 10 to 7 so the mark sits slightly lower while keeping shared chrome math in sync.
Stop double-counting banner height on secondary pages.
Body already reserves the preview strip; main padding now clears only the nav row and logo overhang so inner pages do not stack a second chrome band.
Move the floating logo outside the header containing block.
backdrop-filter on the header trapped position:fixed children so top and margin offsets never moved the mark; pin it to the viewport instead.
Move the floating logo up with marginTop instead of top calc.
The dynamic top calc was not shifting the mark; mirror nav-row flex centring and pull it up 10px with marginTop.
Pin the floating logo top edge for a reliable vertical offset.
Stop relying on translateY(-50%), which was not moving the rendered mark, and place the logo 10px above nav centre explicitly.
Correct the floating logo vertical offset.
Anchor the mark 10px above nav center instead of shifting it down with a transform miscalculation.
Float the logo above the preview banner and raise it 10px.
Use fixed positioning so the mark escapes the nav header stacking context and paints over the red strip.
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.
