Home Projects Portfolio Dashboard Export PDF Log in

Enhancing Security: Migrating Hardcoded Credentials to Environment Variables in Seed Scripts

In software development, especially when dealing with applications that manage user accounts, database seeding is a common practice to populate initial data, often including default administrative users. While convenient, this practice introduces a critical security vulnerability if not handled properly. This post details a recent security enhancement for the Estrella Tour project, focusing on moving sensitive data from hardcoded values to environment variables.

The Problem with Hardcoded Secrets

Many projects utilize seed.ts or similar scripts to bootstrap their databases with essential data, such as an initial administrator account. It's common to define a default admin email and password directly within these scripts for development convenience. However, when these scripts are part of a public or even a private, but widely accessible, repository, hardcoding credentials creates a significant security risk. Anyone with access to the codebase can immediately see and potentially exploit these sensitive details. This exposure can lead to unauthorized access, data breaches, and compromise the integrity of the application.

The Solution: Environment Variables to the Rescue

The industry-standard solution for managing sensitive configuration data like API keys, database credentials, and user passwords is to use environment variables. Environment variables provide a secure way to store configuration outside of your source code, preventing them from being committed to version control. They allow for different values across various deployment environments (development, staging, production) without altering the codebase.

For Estrella Tour, the solution involved replacing hardcoded admin email and password in seed.ts with values loaded from environment variables. This change ensures that sensitive data is never directly visible in the repository.

Implementing the Change in TypeScript/Prisma

To illustrate this, consider a typical seed.ts file that uses Prisma to create an initial user. Before the change, it might look like this:

// Before: In seed.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

async function main() {
  // --- HARDCODED CREDENTIALS ---
  const adminEmail = "[email protected]";
  const adminPassword = "verysecurepassword123"; // DO NOT DO THIS
  // -----------------------------

  const adminUser = await prisma.user.upsert({
    where: { email: adminEmail },
    update: {},
    create: {
      email: adminEmail,
      password: adminPassword, // In a real app, hash this password
      // ... other user fields
    },
  });

  console.log(`Created admin user with email: ${adminUser.email}`);
}

main()
  .catch(e => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

The updated approach leverages process.env to retrieve credentials and includes a crucial validation step to ensure these variables are defined:

// After: In seed.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

async function main() {
  const adminEmail = process.env.SEED_ADMIN_EMAIL;
  const adminPassword = process.env.SEED_ADMIN_PASSWORD;

  if (!adminEmail || !adminPassword) {
    throw new Error("ERROR: SEED_ADMIN_EMAIL and SEED_ADMIN_PASSWORD must be defined in your environment variables.");
  }

  const adminUser = await prisma.user.upsert({
    where: { email: adminEmail },
    update: {},
    create: {
      email: adminEmail,
      password: adminPassword, // Remember to hash passwords in production
      // ... other user fields
    },
  });

  console.log(`Created admin user with email: ${adminUser.email}`);
}

main()
  .catch(e => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

These environment variables would then be defined in a .env file at the root of your project (which should be excluded from version control via .gitignore):

# .env file (DO NOT commit to version control)
[email protected]
SEED_ADMIN_PASSWORD=your_super_secret_password

This change not only removes the sensitive data from the public repository but also makes the seeding process more robust by explicitly failing if the required environment variables are not set.

Actionable Takeaway

Regularly review your codebase, especially configuration and initialization scripts like database seeders, for any hardcoded sensitive information. Prioritize migrating all credentials, API keys, and other secrets to environment variables or a dedicated secrets management system. This simple but critical step significantly enhances the security posture of your application and reduces the risk of credential exposure.


Generated with Gitvlg.com

Enhancing Security: Migrating Hardcoded Credentials to Environment Variables in Seed Scripts
p

pedro marzano

Author

Share: