fix(memory): scope InsightsRepo operations to userId — M2-001/002
Security audit findings and fixes: M2-001 — searchByEmbedding: confirmed already user-scoped via WHERE user_id M2-002 — findByUser: confirmed already user-scoped M2-002 — decayOldInsights: was global (no userId filter); now requires userId param and scopes UPDATE to eq(insights.userId, userId). Added decayAllInsights as a separate system-only method for cron tier management. Additional unscoped operations fixed: - findById: added userId param + AND eq(userId) to prevent cross-user read - update: added userId param + AND eq(userId) to prevent cross-user write - remove: added userId param + AND eq(userId) to prevent cross-user delete - memory.controller getInsight/removeInsight: now pass user.id for ownership - summarization.service: switched tier-management cron to decayAllInsights Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -137,7 +137,7 @@ export class SummarizationService {
|
||||
|
||||
const promoted = await this.logService.logs.promoteToCold(warmCutoff);
|
||||
const purged = await this.logService.logs.purge(coldCutoff);
|
||||
const decayed = await this.memory.insights.decayOldInsights(decayCutoff);
|
||||
const decayed = await this.memory.insights.decayAllInsights(decayCutoff);
|
||||
|
||||
this.logger.log(
|
||||
`Tier management: ${promoted} logs→cold, ${purged} purged, ${decayed} insights decayed`,
|
||||
|
||||
@@ -73,8 +73,8 @@ export class MemoryController {
|
||||
}
|
||||
|
||||
@Get('insights/:id')
|
||||
async getInsight(@Param('id') id: string) {
|
||||
const insight = await this.memory.insights.findById(id);
|
||||
async getInsight(@CurrentUser() user: { id: string }, @Param('id') id: string) {
|
||||
const insight = await this.memory.insights.findById(id, user.id);
|
||||
if (!insight) throw new NotFoundException('Insight not found');
|
||||
return insight;
|
||||
}
|
||||
@@ -97,8 +97,8 @@ export class MemoryController {
|
||||
|
||||
@Delete('insights/:id')
|
||||
@HttpCode(HttpStatus.NO_CONTENT)
|
||||
async removeInsight(@Param('id') id: string) {
|
||||
const deleted = await this.memory.insights.remove(id);
|
||||
async removeInsight(@CurrentUser() user: { id: string }, @Param('id') id: string) {
|
||||
const deleted = await this.memory.insights.remove(id, user.id);
|
||||
if (!deleted) throw new NotFoundException('Insight not found');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user