`$queryRawUnsafe` with Table Name String Interpolation in Watchdog Service
Watchdog query used Prisma's `$queryRawUnsafe` with a table name interpolated directly into the SQL string. Currently mitigated by a feedType whitelist, but creates a latent SQL injection risk that future code changes could trigger.
Description
The getLastComputedFeedPublishedDate method uses Prisma's $queryRawUnsafe, the explicitly unsafe variant that does not parameterize inputs, with a tableName variable interpolated directly into the SQL string:
const tableName = feedType;const result = await this.prismaClient.$queryRawUnsafe<{ publishedAt: Date }[]>(`SELECT t."publishedAt" FROM "Market" m INNER JOIN "${tableName}" t ON t."marketId" = m.id ...`,marketId,);
A whitelist check (knownFeedTypes.includes(feedType)) runs immediately before this call and currently limits feedType to three known table names. However:
The function uses $queryRawUnsafe rather than the safe $queryRaw with Prisma.raw. This means if the whitelist check is ever weakened, removed, or bypassed, the raw string interpolation directly enables SQL injection.
feedType originates from a raw database query result (row.feedType from $queryRaw), which is typically safe but creates a trust chain that is difficult to audit: if the upstream raw query ever returns a manipulated value, it flows directly into an unsafe SQL string.
Impact
Currently mitigated by the whitelist, but the use of $queryRawUnsafe with string interpolation creates a latent SQL injection risk that could be triggered by future code changes.
Recommendation
Replace $queryRawUnsafe with the safe $queryRaw using Prisma.raw for the table name component:
const result = await this.prismaClient.$queryRaw<{ publishedAt: Date }[]>(Prisma.sql`SELECT t."publishedAt" FROM "Market" m INNER JOIN ${Prisma.raw(`"${tableName}"`)} t ON t."marketId" = m.id WHERE m."marketId" = ${marketId} ORDER BY t."publishedAt" DESC LIMIT 1`,);
Retain the whitelist as defense-in-depth.
Resolution
Fixed in PR #3745, $queryRawUnsafe was replaced with $queryRaw + Prisma.sql, and now appears in zero production call sites.

