Convoy: Cross-Tenant Source IDOR Leaks Plaintext Message Broker Credentials
## Summary frain-dev/convoy (all versions up to and including v26.6.2, no patch available) lets any authenticated caller who is authorized on at least one project read ANY OTHER project's "Source" record by ID via GET /api/v1/projects/{projectID}/sources/{sourceID} -- regardless of whether that Source actually belongs to the project named in the URL. The response includes the Source's full PubSub broker configuration in plaintext (AMQP/Kafka/SQS/Google credentials), with no redaction. ## Details `Handler.GetSource` (api/handlers/source.go) resolves the caller's authorization against the {projectID} in the URL via retrieveProject(), then calls `sources.Service.FindSourceByID(ctx, project.UID, sourceID)` (internal/sources/impl.go). That function accepts a projectID parameter but never uses it: func (s *Service) FindSourceByID(ctx context.Context, projectID, id string) (*datastore.Source, error) { row, err := s.repo.FetchSourceByID(ctx, common.StringToPgText(id)) ... } The underlying SQL query (internal/sources/repo/queries.sql, `fetchSourceByID`) has no project_id predicate at all: SELECT ... FROM convoy.sources AS s LEFT JOIN convoy.source_verifiers sv ON s.source_verifier_id = sv.id WHERE s.id = $1 AND s.deleted_at IS NULL So the {projectID} in the URL only gates "is the caller authorized to view *a* project" -- it never re-validates that the fetched Source actually belongs to that project. `LoadSourcesPaged` (the list endpoint) does correctly scope by project; only the singl
GHSA-p5vg-v7mj-f6q4
Primary source · Revision 1
Imported from structured advisory data. Source references identify upstream records or fields; verify affected versions and your deployed configuration.
Security context
Source reference: osv:GHSA-p5vg-v7mj-f6q4
github.com/frain-dev/convoy
Source reference: /affected/0/package/name
- Affected versions
- Not stated in this record
- Fixed versions
- 0.9.3-0.20260724092134-1cc67cd16fb1
Source reference:
/affected/0/ranges - Prerequisites
- Not stated in this record
Structured affected-version data
Original package identities and version rules from this source.
[
{
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "0"
},
{
"fixed": "0.9.3-0.20260724092134-1cc67cd16fb1"
}
]
}
],
"package": {
"name": "github.com/frain-dev/convoy",
"purl": "pkg:golang/github.com/frain-dev/convoy",
"ecosystem": "Go"
},
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-p5vg-v7mj-f6q4/GHSA-p5vg-v7mj-f6q4.json"
}
}
]- Related CVEs
- CVE-2026-81505
Source reference:
/aliases
Publisher severity
high
Source reference: /database_specific/severity
- Event
- #23400 · Revision 1
- Added to Heist Feed
- Publisher date