mirror of
https://github.com/hanzoai/insights.git
synced 2026-11-03 00:52:32 +00:00
Mechanically re-derived: bin/debrand runs over a fresh import of posthog/posthog@fa1a9a60d4 (2026-08-06). The pipeline (.hanzo/workflows), the Dockerfiles and bin/docker* entrypoints, compose files, LLM.md and the squashed initial migration are restored from the shipped tree, same as the previous import. The prune's import-closure guard kept 21 products the new core now imports; dropping them is a refactor now, recorded rather than forced.
1223 lines
57 KiB
YAML
1223 lines
57 KiB
YAML
# Metavariable conventions used in these rules:
|
|
# $METHOD — in sinks/lookups, matches queryset lookup methods; constrained by metavariable-regex to (get|filter|aget)
|
|
# $METHOD / $METHOD2 — in sanitizers/pattern-nots, matches any queryset method (get, filter, aget, exclude, etc.)
|
|
# . ... . (chain ellipsis) — matches zero or more intermediate calls (select_related, prefetch_related, only, defer, etc.)
|
|
# The $METHOD regex is nested inside pattern-either so it only applies to patterns that bind $METHOD.
|
|
# $GOC — in lookups, matches create-like methods; constrained by metavariable-regex to (get_or_create|update_or_create|aget_or_create).
|
|
# In pattern-nots, $METHOD2 with `. ... .` (zero or more calls) covers all methods including
|
|
# get_or_create and update_or_create, so no separate pattern-nots are needed for those.
|
|
rules:
|
|
- id: idor-taint-user-input-to-model-get
|
|
mode: taint
|
|
languages: [python]
|
|
severity: ERROR
|
|
message: |
|
|
IDOR: User input flows to team-scoped model lookup without team filter.
|
|
Fix: Add team__project_id=team.project_id to the query.
|
|
pattern-sources:
|
|
- patterns:
|
|
- pattern-either:
|
|
# Django request params
|
|
- pattern: $REQ.GET.get(...)
|
|
- pattern: $REQ.POST.get(...)
|
|
- pattern: $REQ.GET[...]
|
|
- pattern: $REQ.POST[...]
|
|
- pattern: $REQ.data.get(...)
|
|
- pattern: $REQ.data[...]
|
|
- pattern: $REQ.query_params.get(...)
|
|
- pattern: $REQ.query_params[...]
|
|
# DRF serializer
|
|
- pattern: $SER.validated_data.get(...)
|
|
- pattern: $SER.validated_data[...]
|
|
# URL kwargs (common in DRF)
|
|
- pattern: kwargs.get(...)
|
|
- pattern: kwargs[...]
|
|
# self.kwargs in viewsets
|
|
- pattern: self.kwargs.get(...)
|
|
- pattern: self.kwargs[...]
|
|
pattern-sinks:
|
|
- patterns:
|
|
- pattern-either:
|
|
- patterns:
|
|
- pattern-either:
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk__in=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id__in=$SINK, ...)
|
|
- metavariable-regex:
|
|
metavariable: $METHOD
|
|
regex: ^(get|filter|aget)$
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($MODEL, pk=$SINK, ...)
|
|
- pattern: get_object_or_404($MODEL, id=$SINK, ...)
|
|
- metavariable-regex:
|
|
metavariable: $MODEL
|
|
regex: |
|
|
(?x)(
|
|
AccessControl
|
|
|Account
|
|
|AccountChannelSummary
|
|
|AccountRelationship
|
|
|AccountRelationshipDefinition
|
|
|Action
|
|
|AgentApplication
|
|
|AgentArtifact
|
|
|AgentIdentityCredential
|
|
|AgentIdentityLinkState
|
|
|AgentRevision
|
|
|AgentSandboxInstance
|
|
|AgentSession
|
|
|AgentSessionCredential
|
|
|AgentToolApprovalRequest
|
|
|AgentTransportBinding
|
|
|AgentUser
|
|
|Alert
|
|
|AlertConfiguration
|
|
|Annotation
|
|
|Announcement
|
|
|AnnouncementDelivery
|
|
|ApprovalPolicy
|
|
|BatchExport
|
|
|BatchExportBackfill
|
|
|BatchExportFileDownload
|
|
|BatchExportOnDemand
|
|
|BatchExportSource
|
|
|BatchImport
|
|
|BriefConfig
|
|
|ButtonTile
|
|
|Canvas
|
|
|CanvasBuild
|
|
|CanvasSourceVersion
|
|
|ChangeRequest
|
|
|ChannelContextGeneration
|
|
|ChannelInstructions
|
|
|ChannelStar
|
|
|ClusteringConfig
|
|
|ClusteringJob
|
|
|Cohort
|
|
|CohortBackfillChunk
|
|
|CohortBackfillRun
|
|
|CohortBackfillRunCohort
|
|
|Comment
|
|
|Conversation
|
|
|ConversationRestoreToken
|
|
|CoreMemory
|
|
|CustomerJourney
|
|
|CustomerProfileConfig
|
|
|CustomOAuth2Integration
|
|
|CustomPropertyDefinition
|
|
|CustomPropertySource
|
|
|CustomPropertySyncRun
|
|
|CustomPropertyValue
|
|
|DAG
|
|
|Dashboard
|
|
|DashboardTemplate
|
|
|DashboardWidget
|
|
|DataColorTheme
|
|
|DataModelingJob
|
|
|Dataset
|
|
|DatasetItem
|
|
|DatasetItemVersion
|
|
|DatasetRevision
|
|
|DataWarehouseCredential
|
|
|DataWarehouseJoin
|
|
|DataWarehouseManagedViewSet
|
|
|DataWarehouseModelPath
|
|
|DataWarehouseSavedQuery
|
|
|DataWarehouseSavedQueryColumnAnnotation
|
|
|DataWarehouseSavedQueryDraft
|
|
|DataWarehouseSavedQueryFolder
|
|
|DataWarehouseTable
|
|
|Deployment
|
|
|DeploymentEvent
|
|
|DeploymentProject
|
|
|EarlyAccessFeature
|
|
|EmailMessageMapping
|
|
|EmailReputationSnapshot
|
|
|EvaluationContext
|
|
|Edge
|
|
|Endpoint
|
|
|EnterpriseEventDefinition
|
|
|EnterprisePropertyDefinition
|
|
|EventFilterConfig
|
|
|EventStream
|
|
|EventStreamMember
|
|
|ErrorTrackingAssignmentRule
|
|
|ErrorTrackingBypassRule
|
|
|ErrorTrackingGroupingRule
|
|
|ErrorTrackingIssue
|
|
|ErrorTrackingIssueFingerprintV2
|
|
|ErrorTrackingRelease
|
|
|ErrorTrackingRecommendation
|
|
|ErrorTrackingSettings
|
|
|ErrorTrackingSpikeDetectionConfig
|
|
|ErrorTrackingSpikeEvent
|
|
|ErrorTrackingStackFrame
|
|
|ErrorTrackingSuppressionRule
|
|
|ErrorTrackingSymbolSet
|
|
|Evaluation
|
|
|EvaluationDirectory
|
|
|Experiment
|
|
|ExperimentHoldout
|
|
|ExperimentMetricsRecalculation
|
|
|ExperimentSavedMetric
|
|
|ExportedAsset
|
|
|ExportedRecording
|
|
|ExternalDataJob
|
|
|ExternalDataSchema
|
|
|ExternalDataSchemaOOMEvent
|
|
|ExternalDataSource
|
|
|FeatureFlag
|
|
|TeamExperimentsConfig
|
|
|TeamFeatureFlagDefaultsConfig
|
|
|TeamMCPGatewayConfig
|
|
|TeamSessionSummariesConfig
|
|
|TeamWorkflowsConfig
|
|
|FieldNote
|
|
|FileSystem
|
|
|FileSystemFolderInstructions
|
|
|FileSystemFolderContextGeneration
|
|
|GithubCommentMapping
|
|
|GitHubSyncConfig
|
|
|GitHubSyncPlan
|
|
|GitHubSyncedModel
|
|
|HealthIssue
|
|
|InsightsFlow
|
|
|InsightsFlowBatchJob
|
|
|InsightsFlowRevision
|
|
|InsightsFlowSchedule
|
|
|InsightsFlowTemplate
|
|
|InsightsFunction
|
|
|InsightsFunctionRevision
|
|
|Hook
|
|
|Insight
|
|
|InsightVariable
|
|
|Integration
|
|
|IntegrationRepositoryCacheEntry
|
|
|IntervieweeContext
|
|
|KnowledgeChunk
|
|
|KnowledgeDocument
|
|
|KnowledgeGapSuggestion
|
|
|KnowledgeSource
|
|
|Link
|
|
|LiveDebuggerBreakpoint
|
|
|LogsAlertConfiguration
|
|
|LogsExclusionRule
|
|
|LogsMetricRule
|
|
|LogsRetentionRule
|
|
|LogsView
|
|
|Loop
|
|
|LoopFire
|
|
|LoopTrigger
|
|
|LLMModelConfiguration
|
|
|LLMPrompt
|
|
|LLMPromptLabel
|
|
|LLMProviderKey
|
|
|LLMSkill
|
|
|LLMSkillOwner
|
|
|LLMTraceSummary
|
|
|ManagedWarehouseBackfillPartition
|
|
|ManagedWarehouseSourceJob
|
|
|MarketingAnalyticsGoalMapping
|
|
|MessageCategory
|
|
|MessageRecipientPreference
|
|
|MessageSuppression
|
|
|MessageTemplate
|
|
|Metric
|
|
|RelationshipProposal
|
|
|MCPAnalyticsSubmission
|
|
|MCPAuditEvent
|
|
|MCPGatewayServer
|
|
|MCPIntentClusterSnapshot
|
|
|MCPIntentEmbeddingCache
|
|
|MCPMemberServerRevocation
|
|
|MCPOrgRule
|
|
|MCPServiceAccount
|
|
|MCPServiceAccountServerAccess
|
|
|MCPSession
|
|
|MCPToolPolicy
|
|
|Opportunity
|
|
|OptOutSyncConfig
|
|
|Node
|
|
|NotificationEvent
|
|
|Notebook
|
|
|NotebookNodeRun
|
|
|ObjectMediaPreview
|
|
|ParserRecipe
|
|
|PendingSourceCredential
|
|
|PluginConfig
|
|
|ProductBrief
|
|
|ProductTour
|
|
|ProjectSecretAPIKey
|
|
|PropertyAccessControl
|
|
|QuarantinedIdentifier
|
|
|QueryTabState
|
|
|QuickFilter
|
|
|QuickFilterContext
|
|
|ReplayObservation
|
|
|ReplayObservationLabel
|
|
|ReplayObservationUsage
|
|
|ReplayScanner
|
|
|ReplayScannerPromptSuggestion
|
|
|Repo
|
|
|RepoRoutingRule
|
|
|ReviewReport
|
|
|ReviewReportArtefact
|
|
|ReviewSkillConfig
|
|
|ReviewUserSettings
|
|
|SandboxCustomImage
|
|
|SandboxEnvironment
|
|
|SandboxSession
|
|
|ResourceLink
|
|
|ScoreDefinition
|
|
|SavedHeatmap
|
|
|ScheduledChange
|
|
|SessionGroupSummary
|
|
|SessionRecording
|
|
|SessionRecordingPlaylist
|
|
|SharingConfiguration
|
|
|SignalEmissionRecord
|
|
|SignalReport
|
|
|SignalReportArtefact
|
|
|SignalReportRefund
|
|
|SignalReportTask
|
|
|SignalRepositoryAreaActivity
|
|
|SignalTeamConfig
|
|
|SignalSourceConfig
|
|
|SignalScoutConfig
|
|
|SignalScoutRun
|
|
|SignalScoutEmission
|
|
|SignalScoutNote
|
|
|SignalScoutStructuredOutput
|
|
|SignalScratchpad
|
|
|SignalProjectProfile
|
|
|SingleSessionSummary
|
|
|SlackThreadTaskMapping
|
|
|SourceBatch
|
|
|SourceBatchDuckgresApply
|
|
|SourceDuckgresGroupLease
|
|
|SourceGroupLease
|
|
|StreamlitApp
|
|
|Subscription
|
|
|SubscriptionDelivery
|
|
|Survey
|
|
|SurveyResponseArchive
|
|
|TableCertification
|
|
|Tag
|
|
|Tagger
|
|
|Task
|
|
|TaskActivity
|
|
|TaskArtifact
|
|
|TaskAutomation
|
|
|TaskPresence
|
|
|TaskRun
|
|
|TaskSession
|
|
|TaskThreadMessage
|
|
|TaskThreadMessageMention
|
|
|Channel
|
|
|ChannelFeedMessage
|
|
|EmailChannel
|
|
|EvaluationReport
|
|
|Text
|
|
|Threshold
|
|
|ToleratedHash
|
|
|TeamConversationsTeamsConfig
|
|
|SigningSecret
|
|
|Ticket
|
|
|TicketView
|
|
|TicketViewFavorite
|
|
|ZendeskImportJob
|
|
|ReviewQueue
|
|
|ReviewQueueItem
|
|
|TraceReview
|
|
|TraceReviewScore
|
|
|TracingView
|
|
|UploadedMedia
|
|
|UserInterview
|
|
|UserInterviewTopic
|
|
|UserRepoPreference
|
|
|VisionAction
|
|
|VisionActionRun
|
|
|WarehouseColumnAnnotation
|
|
|WarehouseColumnStatistics
|
|
|WebAnalyticsAchievementProgress
|
|
|WebAnalyticsFilterPreset
|
|
|WebAnalyticsInteraction
|
|
|WebAnalyticsVisit
|
|
|WizardSession
|
|
)$
|
|
- focus-metavariable: $SINK
|
|
pattern-sanitizers:
|
|
- pattern: $M.objects. ... .$METHOD(..., team__project_id=$T, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., effective_project_id=$T, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., team=$T, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., team_id=$T, ...)
|
|
# for_team() is the team filter on fail-closed (TeamScopedManager) models
|
|
- pattern: $M.objects.for_team(...). ... .$METHOD(...)
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($M, ..., team__project_id=$T, ...)
|
|
- pattern: get_object_or_404($M, ..., effective_project_id=$T, ...)
|
|
- pattern: get_object_or_404($M, ..., team=$T, ...)
|
|
- pattern: get_object_or_404($M, ..., team_id=$T, ...)
|
|
metadata:
|
|
category: security
|
|
cwe: 'CWE-639: Authorization Bypass Through User-Controlled Key'
|
|
owasp: 'A01:2021 - Broken Access Control'
|
|
confidence: HIGH
|
|
paths:
|
|
exclude:
|
|
- '**/test*/**'
|
|
- '**/migrations/**'
|
|
- '**/management/**'
|
|
- '**/.semgrep/**'
|
|
- '**/admin/admins/**'
|
|
- '**/backend/admin.py'
|
|
- '**/backend/admin/**'
|
|
|
|
# Combined pattern rule: any lookup without team filter
|
|
- id: idor-lookup-without-team
|
|
patterns:
|
|
- pattern-either:
|
|
- patterns:
|
|
- pattern-either:
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk=$ID, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id=$ID, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk__in=$IDS, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id__in=$IDS, ...)
|
|
- metavariable-regex:
|
|
metavariable: $METHOD
|
|
regex: ^(get|filter|aget)$
|
|
# get_or_create / update_or_create
|
|
- patterns:
|
|
- pattern: $MODEL.objects.$GOC(...)
|
|
- metavariable-regex:
|
|
metavariable: $GOC
|
|
regex: ^(get_or_create|update_or_create|aget_or_create)$
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($MODEL, pk=$ID, ...)
|
|
- pattern: get_object_or_404($MODEL, id=$ID, ...)
|
|
- metavariable-regex:
|
|
metavariable: $MODEL
|
|
regex: |
|
|
(?x)(
|
|
AccessControl
|
|
|Account
|
|
|AccountChannelSummary
|
|
|AccountRelationship
|
|
|AccountRelationshipDefinition
|
|
|Action
|
|
|AgentApplication
|
|
|AgentArtifact
|
|
|AgentIdentityCredential
|
|
|AgentIdentityLinkState
|
|
|AgentRevision
|
|
|AgentSandboxInstance
|
|
|AgentSession
|
|
|AgentSessionCredential
|
|
|AgentToolApprovalRequest
|
|
|AgentTransportBinding
|
|
|AgentUser
|
|
|Alert
|
|
|AlertConfiguration
|
|
|Annotation
|
|
|Announcement
|
|
|AnnouncementDelivery
|
|
|ApprovalPolicy
|
|
|BatchExport
|
|
|BatchExportBackfill
|
|
|BatchExportFileDownload
|
|
|BatchExportOnDemand
|
|
|BatchExportSource
|
|
|BatchImport
|
|
|BriefConfig
|
|
|ButtonTile
|
|
|Canvas
|
|
|CanvasBuild
|
|
|CanvasSourceVersion
|
|
|ChangeRequest
|
|
|ChannelContextGeneration
|
|
|ChannelInstructions
|
|
|ChannelStar
|
|
|ClusteringConfig
|
|
|ClusteringJob
|
|
|Cohort
|
|
|CohortBackfillChunk
|
|
|CohortBackfillRun
|
|
|CohortBackfillRunCohort
|
|
|Comment
|
|
|Conversation
|
|
|ConversationRestoreToken
|
|
|CoreMemory
|
|
|CustomerJourney
|
|
|CustomerProfileConfig
|
|
|CustomOAuth2Integration
|
|
|CustomPropertyDefinition
|
|
|CustomPropertySource
|
|
|CustomPropertySyncRun
|
|
|CustomPropertyValue
|
|
|DAG
|
|
|Dashboard
|
|
|DashboardTemplate
|
|
|DashboardWidget
|
|
|DataColorTheme
|
|
|DataModelingJob
|
|
|Dataset
|
|
|DatasetItem
|
|
|DatasetItemVersion
|
|
|DatasetRevision
|
|
|DataWarehouseCredential
|
|
|DataWarehouseJoin
|
|
|DataWarehouseManagedViewSet
|
|
|DataWarehouseModelPath
|
|
|DataWarehouseSavedQuery
|
|
|DataWarehouseSavedQueryColumnAnnotation
|
|
|DataWarehouseSavedQueryDraft
|
|
|DataWarehouseSavedQueryFolder
|
|
|DataWarehouseTable
|
|
|Deployment
|
|
|DeploymentEvent
|
|
|DeploymentProject
|
|
|EarlyAccessFeature
|
|
|EmailMessageMapping
|
|
|EmailReputationSnapshot
|
|
|EvaluationContext
|
|
|Edge
|
|
|Endpoint
|
|
|EnterpriseEventDefinition
|
|
|EnterprisePropertyDefinition
|
|
|EventFilterConfig
|
|
|EventStream
|
|
|EventStreamMember
|
|
|ErrorTrackingAssignmentRule
|
|
|ErrorTrackingBypassRule
|
|
|ErrorTrackingGroupingRule
|
|
|ErrorTrackingIssue
|
|
|ErrorTrackingIssueFingerprintV2
|
|
|ErrorTrackingRelease
|
|
|ErrorTrackingRecommendation
|
|
|ErrorTrackingSettings
|
|
|ErrorTrackingSpikeDetectionConfig
|
|
|ErrorTrackingSpikeEvent
|
|
|ErrorTrackingStackFrame
|
|
|ErrorTrackingSuppressionRule
|
|
|ErrorTrackingSymbolSet
|
|
|Evaluation
|
|
|EvaluationDirectory
|
|
|Experiment
|
|
|ExperimentHoldout
|
|
|ExperimentMetricsRecalculation
|
|
|ExperimentSavedMetric
|
|
|ExportedAsset
|
|
|ExportedRecording
|
|
|ExternalDataJob
|
|
|ExternalDataSchema
|
|
|ExternalDataSchemaOOMEvent
|
|
|ExternalDataSource
|
|
|FeatureFlag
|
|
|TeamExperimentsConfig
|
|
|TeamFeatureFlagDefaultsConfig
|
|
|TeamMCPGatewayConfig
|
|
|TeamSessionSummariesConfig
|
|
|TeamWorkflowsConfig
|
|
|FieldNote
|
|
|FileSystem
|
|
|FileSystemFolderInstructions
|
|
|FileSystemFolderContextGeneration
|
|
|GithubCommentMapping
|
|
|GitHubSyncConfig
|
|
|GitHubSyncPlan
|
|
|GitHubSyncedModel
|
|
|HealthIssue
|
|
|InsightsFlow
|
|
|InsightsFlowBatchJob
|
|
|InsightsFlowRevision
|
|
|InsightsFlowSchedule
|
|
|InsightsFlowTemplate
|
|
|InsightsFunction
|
|
|InsightsFunctionRevision
|
|
|Hook
|
|
|Insight
|
|
|InsightVariable
|
|
|Integration
|
|
|IntegrationRepositoryCacheEntry
|
|
|IntervieweeContext
|
|
|KnowledgeChunk
|
|
|KnowledgeDocument
|
|
|KnowledgeGapSuggestion
|
|
|KnowledgeSource
|
|
|Link
|
|
|LiveDebuggerBreakpoint
|
|
|Loop
|
|
|LoopFire
|
|
|LoopTrigger
|
|
|LLMModelConfiguration
|
|
|LLMPrompt
|
|
|LLMPromptLabel
|
|
|LLMProviderKey
|
|
|LLMSkill
|
|
|LLMSkillOwner
|
|
|LLMTraceSummary
|
|
|ManagedWarehouseBackfillPartition
|
|
|ManagedWarehouseSourceJob
|
|
|MarketingAnalyticsGoalMapping
|
|
|MessageCategory
|
|
|MessageRecipientPreference
|
|
|MessageSuppression
|
|
|MessageTemplate
|
|
|Metric
|
|
|RelationshipProposal
|
|
|MCPAuditEvent
|
|
|MCPGatewayServer
|
|
|MCPIntentClusterSnapshot
|
|
|MCPIntentEmbeddingCache
|
|
|MCPMemberServerRevocation
|
|
|MCPOrgRule
|
|
|MCPServiceAccount
|
|
|MCPServiceAccountServerAccess
|
|
|MCPSession
|
|
|MCPToolPolicy
|
|
|Opportunity
|
|
|OptOutSyncConfig
|
|
|Node
|
|
|NotificationEvent
|
|
|Notebook
|
|
|NotebookNodeRun
|
|
|ObjectMediaPreview
|
|
|ParserRecipe
|
|
|PendingSourceCredential
|
|
|PluginConfig
|
|
|ProductBrief
|
|
|ProductTour
|
|
|ProjectSecretAPIKey
|
|
|PropertyAccessControl
|
|
|QuarantinedIdentifier
|
|
|QueryTabState
|
|
|QuickFilter
|
|
|QuickFilterContext
|
|
|ReplayObservation
|
|
|ReplayObservationLabel
|
|
|ReplayObservationUsage
|
|
|ReplayScanner
|
|
|ReplayScannerPromptSuggestion
|
|
|Repo
|
|
|RepoRoutingRule
|
|
|ReviewReport
|
|
|ReviewReportArtefact
|
|
|ReviewSkillConfig
|
|
|ReviewUserSettings
|
|
|SandboxCustomImage
|
|
|SandboxEnvironment
|
|
|SandboxSession
|
|
|ResourceLink
|
|
|ScoreDefinition
|
|
|SavedHeatmap
|
|
|ScheduledChange
|
|
|SessionGroupSummary
|
|
|SessionRecording
|
|
|SessionRecordingPlaylist
|
|
|SharingConfiguration
|
|
|SignalEmissionRecord
|
|
|SignalReport
|
|
|SignalReportArtefact
|
|
|SignalReportRefund
|
|
|SignalReportTask
|
|
|SignalRepositoryAreaActivity
|
|
|SignalTeamConfig
|
|
|SignalSourceConfig
|
|
|SignalScoutConfig
|
|
|SignalScoutRun
|
|
|SignalScoutEmission
|
|
|SignalScoutNote
|
|
|SignalScoutStructuredOutput
|
|
|SignalScratchpad
|
|
|SignalProjectProfile
|
|
|SingleSessionSummary
|
|
|SlackThreadTaskMapping
|
|
|SourceBatch
|
|
|SourceBatchDuckgresApply
|
|
|SourceDuckgresGroupLease
|
|
|SourceGroupLease
|
|
|StreamlitApp
|
|
|Subscription
|
|
|SubscriptionDelivery
|
|
|Survey
|
|
|SurveyResponseArchive
|
|
|TableCertification
|
|
|Tag
|
|
|Tagger
|
|
|Task
|
|
|TaskActivity
|
|
|TaskArtifact
|
|
|TaskAutomation
|
|
|TaskPresence
|
|
|TaskRun
|
|
|TaskSession
|
|
|TaskThreadMessage
|
|
|TaskThreadMessageMention
|
|
|Channel
|
|
|ChannelFeedMessage
|
|
|EmailChannel
|
|
|EvaluationReport
|
|
|Text
|
|
|Threshold
|
|
|ToleratedHash
|
|
|TeamConversationsTeamsConfig
|
|
|SigningSecret
|
|
|Ticket
|
|
|TicketView
|
|
|TicketViewFavorite
|
|
|ZendeskImportJob
|
|
|ReviewQueue
|
|
|ReviewQueueItem
|
|
|TraceReview
|
|
|TraceReviewScore
|
|
|TracingView
|
|
|UploadedMedia
|
|
|UserInterview
|
|
|UserInterviewTopic
|
|
|UserRepoPreference
|
|
|VisionAction
|
|
|VisionActionRun
|
|
|WarehouseColumnAnnotation
|
|
|WarehouseColumnStatistics
|
|
|WebAnalyticsAchievementProgress
|
|
|WebAnalyticsFilterPreset
|
|
|WebAnalyticsInteraction
|
|
|WebAnalyticsVisit
|
|
|WizardSession
|
|
)$
|
|
# Exclude when team filter is present
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., team__project_id=$T, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., effective_project_id=$T, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., team=$T, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., team_id=$T, ...)
|
|
# for_team() is the team filter on fail-closed (TeamScopedManager) models
|
|
- pattern-not: $M.objects.for_team(...). ... .$METHOD2(...)
|
|
# get_object_or_404
|
|
- pattern-not: get_object_or_404($M, ..., team__project_id=$T, ...)
|
|
- pattern-not: get_object_or_404($M, ..., effective_project_id=$T, ...)
|
|
- pattern-not: get_object_or_404($M, ..., team=$T, ...)
|
|
- pattern-not: get_object_or_404($M, ..., team_id=$T, ...)
|
|
# Refetching an existing instance by its pk/id attribute
|
|
- pattern-not: $M.objects. ... .$METHOD2(pk=$X.pk, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(pk=$X.id, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(id=$X.pk, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(id=$X.id, ...)
|
|
message: |
|
|
IDOR risk: Lookup on team-scoped model without team filter.
|
|
Fix: Add team_id=team_id or team__project_id=team.project_id to the query.
|
|
languages: [python]
|
|
severity: WARNING
|
|
metadata:
|
|
category: security
|
|
cwe: 'CWE-639: Authorization Bypass Through User-Controlled Key'
|
|
confidence: MEDIUM
|
|
subcategory: audit
|
|
paths:
|
|
exclude:
|
|
- '**/test*/**'
|
|
- '**/migrations/**'
|
|
- '**/management/**'
|
|
- '**/.semgrep/**'
|
|
- '**/tasks/**'
|
|
- '**/temporal/**'
|
|
- '**/dags/**'
|
|
- '**/models/**'
|
|
- '**/signals.py'
|
|
- '**/admin/admins/**'
|
|
- '**/backend/admin.py'
|
|
- '**/backend/admin/**'
|
|
|
|
# Organization-scoped model taint rule
|
|
- id: idor-taint-user-input-to-org-model
|
|
mode: taint
|
|
languages: [python]
|
|
severity: ERROR
|
|
message: |
|
|
IDOR: User input flows to organization-scoped model lookup without organization filter.
|
|
Fix: Add organization=organization or organization_id=organization_id to the query.
|
|
For RoleMembership, use role__organization= or role__organization_id=.
|
|
pattern-sources:
|
|
- patterns:
|
|
- pattern-either:
|
|
- pattern: $REQ.GET.get(...)
|
|
- pattern: $REQ.POST.get(...)
|
|
- pattern: $REQ.GET[...]
|
|
- pattern: $REQ.POST[...]
|
|
- pattern: $REQ.data.get(...)
|
|
- pattern: $REQ.data[...]
|
|
- pattern: $REQ.query_params.get(...)
|
|
- pattern: $REQ.query_params[...]
|
|
- pattern: $SER.validated_data.get(...)
|
|
- pattern: $SER.validated_data[...]
|
|
- pattern: kwargs.get(...)
|
|
- pattern: kwargs[...]
|
|
- pattern: self.kwargs.get(...)
|
|
- pattern: self.kwargs[...]
|
|
pattern-sinks:
|
|
- patterns:
|
|
- pattern-either:
|
|
- patterns:
|
|
- pattern-either:
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk__in=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id__in=$SINK, ...)
|
|
- metavariable-regex:
|
|
metavariable: $METHOD
|
|
regex: ^(get|filter|aget)$
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($MODEL, pk=$SINK, ...)
|
|
- pattern: get_object_or_404($MODEL, id=$SINK, ...)
|
|
- metavariable-regex:
|
|
metavariable: $MODEL
|
|
regex: |
|
|
(?x)(
|
|
CIMDVerificationToken
|
|
|IdentityProviderConfig
|
|
|LegalDocument
|
|
|OrganizationMembership
|
|
|OrganizationDomain
|
|
|OrganizationIntegration
|
|
|OrganizationInvite
|
|
|Plugin
|
|
|Project
|
|
|ProxyRecord
|
|
|ReplayQuotaGrant
|
|
|Role
|
|
|RoleExternalReference
|
|
|RoleMembership
|
|
)$
|
|
- focus-metavariable: $SINK
|
|
pattern-sanitizers:
|
|
- pattern: $M.objects. ... .$METHOD(..., organization=$O, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., organization_id=$O, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., organization__id=$O, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., role__organization=$O, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., role__organization_id=$O, ...)
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($M, ..., organization=$O, ...)
|
|
- pattern: get_object_or_404($M, ..., organization_id=$O, ...)
|
|
- pattern: get_object_or_404($M, ..., organization__id=$O, ...)
|
|
- pattern: get_object_or_404($M, ..., role__organization=$O, ...)
|
|
- pattern: get_object_or_404($M, ..., role__organization_id=$O, ...)
|
|
metadata:
|
|
category: security
|
|
cwe: 'CWE-639: Authorization Bypass Through User-Controlled Key'
|
|
owasp: 'A01:2021 - Broken Access Control'
|
|
confidence: HIGH
|
|
paths:
|
|
exclude:
|
|
- '**/test*/**'
|
|
- '**/migrations/**'
|
|
- '**/management/**'
|
|
- '**/.semgrep/**'
|
|
- '**/admin/admins/**'
|
|
- '**/backend/admin.py'
|
|
- '**/backend/admin/**'
|
|
|
|
# Organization-scoped model lookup rule
|
|
- id: idor-lookup-without-org
|
|
patterns:
|
|
- pattern-either:
|
|
- patterns:
|
|
- pattern-either:
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk=$ID, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id=$ID, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk__in=$IDS, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id__in=$IDS, ...)
|
|
- metavariable-regex:
|
|
metavariable: $METHOD
|
|
regex: ^(get|filter|aget)$
|
|
- patterns:
|
|
- pattern: $MODEL.objects.$GOC(...)
|
|
- metavariable-regex:
|
|
metavariable: $GOC
|
|
regex: ^(get_or_create|update_or_create|aget_or_create)$
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($MODEL, pk=$ID, ...)
|
|
- pattern: get_object_or_404($MODEL, id=$ID, ...)
|
|
- metavariable-regex:
|
|
metavariable: $MODEL
|
|
regex: |
|
|
(?x)(
|
|
CIMDVerificationToken
|
|
|IdentityProviderConfig
|
|
|LegalDocument
|
|
|OrganizationMembership
|
|
|OrganizationDomain
|
|
|OrganizationIntegration
|
|
|OrganizationInvite
|
|
|Plugin
|
|
|Project
|
|
|ProxyRecord
|
|
|ReplayQuotaGrant
|
|
|Role
|
|
|RoleExternalReference
|
|
|RoleMembership
|
|
)$
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., organization=$O, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., organization_id=$O, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., organization__id=$O, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., role__organization=$O, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., role__organization_id=$O, ...)
|
|
# get_object_or_404
|
|
- pattern-not: get_object_or_404($M, ..., organization=$O, ...)
|
|
- pattern-not: get_object_or_404($M, ..., organization_id=$O, ...)
|
|
- pattern-not: get_object_or_404($M, ..., organization__id=$O, ...)
|
|
- pattern-not: get_object_or_404($M, ..., role__organization=$O, ...)
|
|
- pattern-not: get_object_or_404($M, ..., role__organization_id=$O, ...)
|
|
# Refetching an existing instance by its pk/id attribute
|
|
- pattern-not: $M.objects. ... .$METHOD2(pk=$X.pk, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(pk=$X.id, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(id=$X.pk, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(id=$X.id, ...)
|
|
message: |
|
|
IDOR risk: Lookup on organization-scoped model without organization filter.
|
|
Fix: Add organization_id=organization_id or organization=organization to the query.
|
|
For RoleMembership, use role__organization= or role__organization_id=.
|
|
languages: [python]
|
|
severity: WARNING
|
|
metadata:
|
|
category: security
|
|
cwe: 'CWE-639: Authorization Bypass Through User-Controlled Key'
|
|
confidence: MEDIUM
|
|
subcategory: audit
|
|
paths:
|
|
exclude:
|
|
- '**/test*/**'
|
|
- '**/migrations/**'
|
|
- '**/management/**'
|
|
- '**/.semgrep/**'
|
|
- '**/tasks/**'
|
|
- '**/temporal/**'
|
|
- '**/dags/**'
|
|
- '**/models/**'
|
|
- '**/signals.py'
|
|
- '**/admin/admins/**'
|
|
- '**/backend/admin.py'
|
|
- '**/backend/admin/**'
|
|
|
|
# User-scoped model taint rule
|
|
- id: idor-taint-user-input-to-user-model
|
|
mode: taint
|
|
languages: [python]
|
|
severity: ERROR
|
|
message: |
|
|
IDOR: User input flows to user-scoped model lookup without user filter.
|
|
Fix: Add user=user or user_id=user_id to the query.
|
|
pattern-sources:
|
|
- patterns:
|
|
- pattern-either:
|
|
- pattern: $REQ.GET.get(...)
|
|
- pattern: $REQ.POST.get(...)
|
|
- pattern: $REQ.GET[...]
|
|
- pattern: $REQ.POST[...]
|
|
- pattern: $REQ.data.get(...)
|
|
- pattern: $REQ.data[...]
|
|
- pattern: $REQ.query_params.get(...)
|
|
- pattern: $REQ.query_params[...]
|
|
- pattern: $SER.validated_data.get(...)
|
|
- pattern: $SER.validated_data[...]
|
|
- pattern: kwargs.get(...)
|
|
- pattern: kwargs[...]
|
|
- pattern: self.kwargs.get(...)
|
|
- pattern: self.kwargs[...]
|
|
pattern-sinks:
|
|
- patterns:
|
|
- pattern-either:
|
|
- patterns:
|
|
- pattern-either:
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk__in=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id__in=$SINK, ...)
|
|
- metavariable-regex:
|
|
metavariable: $METHOD
|
|
regex: ^(get|filter|aget)$
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($MODEL, pk=$SINK, ...)
|
|
- pattern: get_object_or_404($MODEL, id=$SINK, ...)
|
|
- metavariable-regex:
|
|
metavariable: $MODEL
|
|
regex: |
|
|
(?x)(
|
|
CommunitySkillVote
|
|
|DashboardPrivilege
|
|
|PersonalAPIKey
|
|
|ScoreDefinitionVersion
|
|
|SignalUserAutonomyConfig
|
|
|TaskPin
|
|
|UserPushToken
|
|
|WebauthnCredential
|
|
)$
|
|
- focus-metavariable: $SINK
|
|
pattern-sanitizers:
|
|
- pattern: $M.objects. ... .$METHOD(..., user=$U, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., user_id=$U, ...)
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($M, ..., user=$U, ...)
|
|
- pattern: get_object_or_404($M, ..., user_id=$U, ...)
|
|
metadata:
|
|
category: security
|
|
cwe: 'CWE-639: Authorization Bypass Through User-Controlled Key'
|
|
owasp: 'A01:2021 - Broken Access Control'
|
|
confidence: HIGH
|
|
paths:
|
|
exclude:
|
|
- '**/test*/**'
|
|
- '**/migrations/**'
|
|
- '**/management/**'
|
|
- '**/.semgrep/**'
|
|
- '**/admin/admins/**'
|
|
- '**/backend/admin.py'
|
|
- '**/backend/admin/**'
|
|
|
|
# User-scoped model lookup rule
|
|
- id: idor-lookup-without-user
|
|
patterns:
|
|
- pattern-either:
|
|
- patterns:
|
|
- pattern-either:
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk=$ID, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id=$ID, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk__in=$IDS, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id__in=$IDS, ...)
|
|
- metavariable-regex:
|
|
metavariable: $METHOD
|
|
regex: ^(get|filter|aget)$
|
|
- patterns:
|
|
- pattern: $MODEL.objects.$GOC(...)
|
|
- metavariable-regex:
|
|
metavariable: $GOC
|
|
regex: ^(get_or_create|update_or_create|aget_or_create)$
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($MODEL, pk=$ID, ...)
|
|
- pattern: get_object_or_404($MODEL, id=$ID, ...)
|
|
- metavariable-regex:
|
|
metavariable: $MODEL
|
|
regex: |
|
|
(?x)(
|
|
CommunitySkillVote
|
|
|DashboardPrivilege
|
|
|PersonalAPIKey
|
|
|ScoreDefinitionVersion
|
|
|SignalUserAutonomyConfig
|
|
|TaskPin
|
|
|UserPushToken
|
|
|WebauthnCredential
|
|
)$
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., user=$U, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., user_id=$U, ...)
|
|
# get_object_or_404
|
|
- pattern-not: get_object_or_404($M, ..., user=$U, ...)
|
|
- pattern-not: get_object_or_404($M, ..., user_id=$U, ...)
|
|
# Refetching an existing instance by its pk/id attribute
|
|
- pattern-not: $M.objects. ... .$METHOD2(pk=$X.pk, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(pk=$X.id, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(id=$X.pk, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(id=$X.id, ...)
|
|
message: |
|
|
IDOR risk: Lookup on user-scoped model without user filter.
|
|
Fix: Add user_id=user_id or user=user to the query.
|
|
languages: [python]
|
|
severity: WARNING
|
|
metadata:
|
|
category: security
|
|
cwe: 'CWE-639: Authorization Bypass Through User-Controlled Key'
|
|
confidence: MEDIUM
|
|
subcategory: audit
|
|
paths:
|
|
exclude:
|
|
- '**/test*/**'
|
|
- '**/migrations/**'
|
|
- '**/management/**'
|
|
- '**/.semgrep/**'
|
|
- '**/tasks/**'
|
|
- '**/temporal/**'
|
|
- '**/dags/**'
|
|
- '**/models/**'
|
|
- '**/signals.py'
|
|
- '**/admin/admins/**'
|
|
- '**/backend/admin.py'
|
|
- '**/backend/admin/**'
|
|
|
|
# Composite user+team scoped model taint rule
|
|
- id: idor-taint-user-input-to-user-team-model
|
|
mode: taint
|
|
languages: [python]
|
|
severity: ERROR
|
|
message: |
|
|
IDOR: User input flows to user+team-scoped model lookup without both filters.
|
|
Fix: Add BOTH user= (or user_id=) AND team= (or team_id=) to the query.
|
|
pattern-sources:
|
|
- patterns:
|
|
- pattern-either:
|
|
- pattern: $REQ.GET.get(...)
|
|
- pattern: $REQ.POST.get(...)
|
|
- pattern: $REQ.GET[...]
|
|
- pattern: $REQ.POST[...]
|
|
- pattern: $REQ.data.get(...)
|
|
- pattern: $REQ.data[...]
|
|
- pattern: $REQ.query_params.get(...)
|
|
- pattern: $REQ.query_params[...]
|
|
- pattern: $SER.validated_data.get(...)
|
|
- pattern: $SER.validated_data[...]
|
|
- pattern: kwargs.get(...)
|
|
- pattern: kwargs[...]
|
|
- pattern: self.kwargs.get(...)
|
|
- pattern: self.kwargs[...]
|
|
pattern-sinks:
|
|
- patterns:
|
|
- pattern-either:
|
|
- patterns:
|
|
- pattern-either:
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk__in=$SINK, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id__in=$SINK, ...)
|
|
- metavariable-regex:
|
|
metavariable: $METHOD
|
|
regex: ^(get|filter|aget)$
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($MODEL, pk=$SINK, ...)
|
|
- pattern: get_object_or_404($MODEL, id=$SINK, ...)
|
|
- metavariable-regex:
|
|
metavariable: $MODEL
|
|
regex: |
|
|
(?x)(
|
|
AgentMemory
|
|
|FileSystemShortcut
|
|
|FileSystemViewLog
|
|
|InsightViewed
|
|
|KernelRuntime
|
|
|MCPServerInstallation
|
|
|PersistedFolder
|
|
|Reminder
|
|
|SessionRecordingViewed
|
|
|UserHomeSettings
|
|
|UserProductList
|
|
|UserScenePersonalisation
|
|
|WebAnalyticsUserConfig
|
|
)$
|
|
- focus-metavariable: $SINK
|
|
pattern-sanitizers:
|
|
# Must have BOTH user AND team filters (all orderings)
|
|
- pattern: $M.objects. ... .$METHOD(..., user=$U, ..., team=$T, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., user=$U, ..., team_id=$T, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., user_id=$U, ..., team=$T, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., user_id=$U, ..., team_id=$T, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., team=$T, ..., user=$U, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., team=$T, ..., user_id=$U, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., team_id=$T, ..., user=$U, ...)
|
|
- pattern: $M.objects. ... .$METHOD(..., team_id=$T, ..., user_id=$U, ...)
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($M, ..., user=$U, ..., team=$T, ...)
|
|
- pattern: get_object_or_404($M, ..., user=$U, ..., team_id=$T, ...)
|
|
- pattern: get_object_or_404($M, ..., user_id=$U, ..., team=$T, ...)
|
|
- pattern: get_object_or_404($M, ..., user_id=$U, ..., team_id=$T, ...)
|
|
- pattern: get_object_or_404($M, ..., team=$T, ..., user=$U, ...)
|
|
- pattern: get_object_or_404($M, ..., team=$T, ..., user_id=$U, ...)
|
|
- pattern: get_object_or_404($M, ..., team_id=$T, ..., user=$U, ...)
|
|
- pattern: get_object_or_404($M, ..., team_id=$T, ..., user_id=$U, ...)
|
|
metadata:
|
|
category: security
|
|
cwe: 'CWE-639: Authorization Bypass Through User-Controlled Key'
|
|
owasp: 'A01:2021 - Broken Access Control'
|
|
confidence: HIGH
|
|
paths:
|
|
exclude:
|
|
- '**/test*/**'
|
|
- '**/migrations/**'
|
|
- '**/management/**'
|
|
- '**/.semgrep/**'
|
|
- '**/admin/admins/**'
|
|
- '**/backend/admin.py'
|
|
- '**/backend/admin/**'
|
|
|
|
# Composite user+team scoped model lookup rule
|
|
- id: idor-lookup-without-user-and-team
|
|
patterns:
|
|
- pattern-either:
|
|
- patterns:
|
|
- pattern-either:
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk=$ID, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id=$ID, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(pk__in=$IDS, ...)
|
|
- pattern: $MODEL.objects. ... .$METHOD(id__in=$IDS, ...)
|
|
- metavariable-regex:
|
|
metavariable: $METHOD
|
|
regex: ^(get|filter|aget)$
|
|
- patterns:
|
|
- pattern: $MODEL.objects.$GOC(...)
|
|
- metavariable-regex:
|
|
metavariable: $GOC
|
|
regex: ^(get_or_create|update_or_create|aget_or_create)$
|
|
# get_object_or_404
|
|
- pattern: get_object_or_404($MODEL, pk=$ID, ...)
|
|
- pattern: get_object_or_404($MODEL, id=$ID, ...)
|
|
- metavariable-regex:
|
|
metavariable: $MODEL
|
|
regex: |
|
|
(?x)(
|
|
AgentMemory
|
|
|FileSystemShortcut
|
|
|FileSystemViewLog
|
|
|InsightViewed
|
|
|KernelRuntime
|
|
|PersistedFolder
|
|
|Reminder
|
|
|SessionRecordingViewed
|
|
|UserHomeSettings
|
|
|UserProductList
|
|
|UserScenePersonalisation
|
|
|WebAnalyticsUserConfig
|
|
)$
|
|
# Exclude when BOTH user AND team filters are present
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., user=$U, ..., team=$T, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., user=$U, ..., team_id=$T, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., user_id=$U, ..., team=$T, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., user_id=$U, ..., team_id=$T, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., team=$T, ..., user=$U, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., team=$T, ..., user_id=$U, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., team_id=$T, ..., user=$U, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(..., team_id=$T, ..., user_id=$U, ...)
|
|
# get_object_or_404
|
|
- pattern-not: get_object_or_404($M, ..., user=$U, ..., team=$T, ...)
|
|
- pattern-not: get_object_or_404($M, ..., user=$U, ..., team_id=$T, ...)
|
|
- pattern-not: get_object_or_404($M, ..., user_id=$U, ..., team=$T, ...)
|
|
- pattern-not: get_object_or_404($M, ..., user_id=$U, ..., team_id=$T, ...)
|
|
- pattern-not: get_object_or_404($M, ..., team=$T, ..., user=$U, ...)
|
|
- pattern-not: get_object_or_404($M, ..., team=$T, ..., user_id=$U, ...)
|
|
- pattern-not: get_object_or_404($M, ..., team_id=$T, ..., user=$U, ...)
|
|
- pattern-not: get_object_or_404($M, ..., team_id=$T, ..., user_id=$U, ...)
|
|
# Refetching an existing instance by its pk/id attribute
|
|
- pattern-not: $M.objects. ... .$METHOD2(pk=$X.pk, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(pk=$X.id, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(id=$X.pk, ...)
|
|
- pattern-not: $M.objects. ... .$METHOD2(id=$X.id, ...)
|
|
message: |
|
|
IDOR risk: Lookup on user+team-scoped model without BOTH user AND team filters.
|
|
Fix: Add BOTH user_id= (or user=) AND team_id= (or team=) to the query.
|
|
languages: [python]
|
|
severity: WARNING
|
|
metadata:
|
|
category: security
|
|
cwe: 'CWE-639: Authorization Bypass Through User-Controlled Key'
|
|
confidence: MEDIUM
|
|
subcategory: audit
|
|
paths:
|
|
exclude:
|
|
- '**/test*/**'
|
|
- '**/migrations/**'
|
|
- '**/management/**'
|
|
- '**/.semgrep/**'
|
|
- '**/tasks/**'
|
|
- '**/temporal/**'
|
|
- '**/dags/**'
|
|
- '**/models/**'
|
|
- '**/signals.py'
|
|
- '**/admin/admins/**'
|
|
- '**/backend/admin.py'
|
|
- '**/backend/admin/**'
|