T09 · Insecure Skill Coding Practices
- Location
SKILL.md:450- Finding
Unrestricted bulk database deletion in generated test teardown
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:349,SKILL.md:450-454,SKILL.md:579, andSKILL.md:615
Vulnerability Type: Unguarded destructive database operation
Risk Level: HighVulnerable Code
typescript const prisma = new PrismaClient();typescript export async function clearTestData() { // Delete in reverse dependency order (children before parents) await prisma.order.deleteMany(); await prisma.post.deleteMany(); await prisma.user.deleteMany(); }The generated report also recommends automatic invocation during test teardown:
typescript afterAll(clearTestData);Technical Analysis
The generated
PrismaClientuses the application's ambient Prisma configuration, whileclearTestData()performs unfiltereddeleteMany()operations. Each operation deletes every accessible row in the corresponding table.The cleanup function does not verify that:
- The process is running in a test environment.
- The configured database is a dedicated test database.
- The database host or name belongs to an approved test allowlist.
- The records were created by the current test run.
- The user explicitly authorized destructive cleanup.
The skill also recommends connecting the function to
afterAll, causing it to run automatically. If a developer accidentally supplies production or shared-environment database credentials, normal test execution can therefore trigger destructive deletion without an additional confirmation step.Attack Path
- A user follows the skill and generates Prisma test factories.
- The generated setup constructs
PrismaClientfrom the current environment configuration. - The user or CI system runs the test suite with a production, staging, or shared database URL due to configuration error or environment-variable manipulation.
- The test framework invokes
afterAll(clearTestData). deleteMany()executes without ...[truncated 815 chars]
- Remediation
View remediation
Remediation Suggestions
- Make cleanup explicitly opt-in rather than automatically registering it with
afterAll. - Fail closed unless the process is demonstrably running in a test environment:
typescript function assertSafeTestDatabase() { if (process.env.NODE_ENV !== 'test') { throw new Error('Database cleanup is restricted to NODE_ENV=test'); } const databaseUrl = process.env.DATABASE_URL; if (!databaseUrl) { throw new Error('DATABASE_URL is required'); } const parsed = new URL(databaseUrl); const approvedDatabases = new Set(['app_test', 'app_test_ci']); if (!approvedDatabases.has(parsed.pathname.replace(/^\//, ''))) { throw new Error('Refusing to clean a non-approved database'); } } - Invoke the guard immediately before every destructive operation.
- Tag generated records with a unique test-run identifier and delete only records carrying that identifier.
- Prefer transaction-based isolation followed by rollback rather than table-wide deletion.
- Use a dedicated database account restricted to a dedicated test database.
- Require an additional explicit environment variable, such as
ALLOW_TEST_DATA_DELETION=true, for destructive cleanup. - Prevent test and CI credentials from accessing production databases through network and database-level access controls.
- Make cleanup explicitly opt-in rather than automatically registering it with
