npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

prisma-firewall

v0.1.1

Published

A security firewall middleware for Prisma. Block dangerous queries before they hit your database!

Downloads

254

Readme

prisma-firewall 🔒

A security firewall for Prisma. Blocks dangerous queries before they hit your database.

The Problem

Prisma makes database access easy. Too easy sometimes.

A single line like this wipes your entire users table with no confirmation and no warning:

await prisma.user.deleteMany()

Or this returns every user in your database — passwords, tokens, sensitive fields — to whoever called it:

await prisma.user.findMany()

These aren't hypothetical risks. They happen from bugs, tired developers, bad inputs, and compromised dependencies. prisma-firewall sits between your code and your database and stops them before they cause damage.


Installation

npm install prisma-firewall

Setup

Wrap your Prisma client with withFirewall:

import { PrismaClient } from '@prisma/client'
import { withFirewall } from 'prisma-firewall'

const baseClient = new PrismaClient()

export const prisma = withFirewall(baseClient, {
  rules: {
    blockDeleteWithoutWhere: true,
    blockUpdateWithoutWhere: true,
    blockDeleteSingleWithoutId: true,
    blockUpdateSingleWithoutId: true,
    blockFindManyWithoutLimit: true,
    maxRows: 1000,
    blockDangerousRawPatterns: true,
    blockOperatorInjection: true,
    auditLog: true
  }
})

That's it. Use prisma exactly as you normally would. The firewall runs silently in the background.


What It Blocks

Delete without a where clause

// BLOCKED — deletes every row in the table
await prisma.user.deleteMany()

// ALLOWED
await prisma.user.deleteMany({ where: { active: false } })

Update without a where clause

// BLOCKED — updates every row in the table
await prisma.user.updateMany({ data: { role: 'ADMIN' } })

// ALLOWED
await prisma.user.updateMany({
  where: { trialExpired: true },
  data: { role: 'FREE' }
})

Delete without an id

// BLOCKED
await prisma.user.delete({ where: { email: '[email protected]' } })

// ALLOWED
await prisma.user.delete({ where: { id: '123' } })

findMany with no limit

// Automatically capped to 1000 rows
await prisma.user.findMany()

// Your own limit is respected if under maxRows
await prisma.user.findMany({ take: 50 })

Sensitive fields in select

// password and token are silently stripped before the query runs
await prisma.user.findMany({
  select: {
    id: true,
    email: true,
    password: true,
    token: true
  }
})

Dangerous raw queries

// BLOCKED
await prisma.$executeRaw`DROP TABLE users`
await prisma.$executeRaw`TRUNCATE TABLE orders`

Operator injection

A less known but real attack. Instead of sending a plain password string, an attacker sends this:

{
  "email": "[email protected]",
  "password": { "not": "" }
}

Your code looks harmless:

const user = await prisma.user.findFirst({
  where: { email, password }
})

But Prisma accepts { "not": "" } as a valid operator, meaning find the user where password is NOT empty. Authentication bypassed without knowing the password.

blockOperatorInjection catches this before it reaches the database.


All Rules

| Rule | Type | Description | |------|------|-------------| | blockDeleteWithoutWhere | boolean | Blocks deleteMany with no where clause | | blockUpdateWithoutWhere | boolean | Blocks updateMany with no where clause | | blockDeleteSingleWithoutId | boolean | Blocks delete with no id in where | | blockUpdateSingleWithoutId | boolean | Blocks update with no id in where | | blockFindManyWithoutLimit | boolean | Caps findMany results to maxRows | | maxRows | number | Maximum rows findMany can return (default 1000) | | blockRawQueries | boolean | Blocks all $queryRaw and $executeRaw | | blockDangerousRawPatterns | boolean | Blocks DROP, TRUNCATE, ALTER in raw queries | | blockOperatorInjection | boolean | Blocks Prisma operator injection attacks | | blockedFields | string[] | Fields to strip from select clauses | | rateLimit | object | Rate limits specific operations per minute | | auditLog | boolean | Logs every query with timestamp |

Default blocked fields

If you don't provide blockedFields, these are stripped automatically:

password, passwordHash, token, accessToken, refreshToken,
secret, apiKey, privateKey, ssn, creditCard, cardNumber, cvv

Rate Limiting

withFirewall(baseClient, {
  rules: {
    rateLimit: {
      operations: ['deleteMany', 'updateMany'],
      maxPerMinute: 10
    }
  }
})

Custom Alerting

By default the firewall logs to the console. Override onBlock to send alerts anywhere:

withFirewall(baseClient, {
  rules: { ... },
  onBlock: (details) => {
    fetch('your-slack-webhook', {
      method: 'POST',
      body: JSON.stringify({
        text: `Blocked ${details.operation} on ${details.model}: ${details.reason}`
      })
    })
  }
})

Custom Audit Logging

Override onAudit to send audit logs to your own monitoring service:

withFirewall(baseClient, {
  rules: { auditLog: true },
  onAudit: (details) => {
    myLogger.log(details)
  }
})

What a Blocked Query Looks Like

PRISMA FIREWALL — QUERY BLOCKED
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   Model:      User
   Operation:  deleteMany
   Reason:     deleteMany without a where clause will delete every row in the table
   Rule:       BLOCK_DELETE_WITHOUT_WHERE
   Timestamp:  2026-04-09T03:26:20.640Z
   Args:       {}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Who Is This For

  • Solo developers who want a safety net on destructive queries
  • Small teams where anyone can push a migration or script
  • Production apps where a single bad query can cause real damage
  • Anyone building on Prisma who wants peace of mind

License

MIT