Aikido

How to avoid SELECT * in SQL: preventing data leaks

Performance

Rule
Avoid SELECT * in SQL queries.
SELECT * in production code makes applications
fragile to schema changes and obscures data dependencies.

Supported languages: 45+

Introduction

Using SELECT * in production queries retrieves every column from a table, including columns your application doesn't use. When database schemas evolve and new columns are added (including sensitive data like passwords or PII), queries using SELECT * automatically start retrieving them without code changes. This creates security vulnerabilities and breaks assumptions in your application logic.

Why it matters

Performance impact: Retrieving unnecessary columns increases query execution time, network transfer size, and memory consumption. A table with 50 columns where you only need 5 means you're transferring 10x more data than necessary, degrading response times and increasing infrastructure costs.

Security implications: New columns added to tables (audit fields, internal flags, sensitive user data) are automatically exposed through SELECT * queries. Your API might start leaking password hashes, SSNs, or internal business data that was never intended for that endpoint.

Code maintainability: When SELECT * queries break after schema changes, the failure happens at runtime, not compile time. A new non-nullable column or renamed field causes production errors. Explicit column lists make dependencies clear and break builds when schemas change incompatibly.

Code examples

❌ Non-compliant:

async function getUserProfile(userId) {
    const query = 'SELECT * FROM users WHERE id = ?';
    const [user] = await db.execute(query, [userId]);

    return {
        name: user.name,
        email: user.email,
        createdAt: user.created_at
    };
}

Why it's wrong: This retrieves all columns including potentially sensitive fields like password_hash, ssn, internal_notes, or deleted_at. As the schema grows, this query becomes slower and exposes more data, yet the application only uses three fields.

✅ Compliant:

async function getUserProfile(userId) {
    const query = `
        SELECT name, email, created_at
        FROM users
        WHERE id = ?
    `;
    const [user] = await db.execute(query, [userId]);

    return {
        name: user.name,
        email: user.email,
        createdAt: user.created_at
    };
}

Conclusion

Always specify explicit column lists in SQL queries. This prevents data leaks, improves performance, and makes dependencies between code and schema clear. The small upfront cost of typing column names prevents entire classes of security and performance issues.

FAQs

Got Questions?

When is SELECT * acceptable?

Only in ad-hoc queries during development or debugging, never in production code. For data migration scripts or one-off reports where you genuinely need all columns, SELECT * is reasonable. For application code, always use explicit column lists even if you currently need all columns, because schema changes are inevitable.

What about ORMs that generate SELECT * queries?

Configure your ORM to select specific fields. Most ORMs (Sequelize, TypeORM, Prisma, SQLAlchemy) support field selection: User.findOne({ attributes: ['name', 'email'] }) or prisma.user.findUnique({ select: { name: true, email: true } }). Always use these options to control what data is retrieved.

Does SELECT * impact database performance significantly?

Yes, especially with wide tables. Databases must read more pages from disk, indexes can't be used as effectively, and query result sets consume more memory in the database buffer pool. Network transfer time increases proportionally to data size. For tables with TEXT or BLOB columns, the impact can be severe.

How do I handle queries where I need most columns?

List them explicitly. Use your IDE's auto-complete or query the information_schema to generate the column list. Some teams create view objects or use database views that define the exact columns needed for each use case. The clarity and safety of explicit lists outweigh the minor inconvenience.

How do I detect SELECT * in my codebase?

Search for the pattern SELECT * (case-insensitive) in your codebase. Many static analysis tools and database query analyzers can flag these. During code review, reject any PR containing SELECT * in application code. Some teams use pre-commit hooks or CI checks to automatically detect and block these patterns.

Get secure for free

Secure your code, cloud, and runtime in one central system.
Find and fix vulnerabilities fast automatically.

No credit card required | Scan results in 32secs.