excessive-data-exposure-anti-pattern

Security anti-pattern for excessive data exposure (CWE-200). Use when generating or reviewing API responses, database queries, or data serialization. Detects returning more data than necessary including internal fields, sensitive attributes, and related records.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "excessive-data-exposure-anti-pattern" with this command: npx skills add igbuend/grimbard/igbuend-grimbard-excessive-data-exposure-anti-pattern

Excessive Data Exposure Anti-Pattern

Severity: High

Summary

Excessive Data Exposure occurs when APIs return more data than necessary for client functionality. This happens when endpoints serialize raw database objects or model classes without filtering sensitive fields. Attackers intercept API responses to access exposed PII, credentials, and internal system details, even when client-side UI hides this data.

The Anti-Pattern

Never serialize and return entire database objects or internal models. This exposes all object properties, including sensitive ones, assuming the client will filter what it needs.

BAD Code Example

# VULNERABLE: Returns the entire raw database user object.
from flask import jsonify

class User:
    def __init__(self, id, username, email, password_hash, ssn, is_admin):
        self.id = id
        self.username = username
        self.email = email
        self.password_hash = password_hash
        self.ssn = ssn
        self.is_admin = is_admin

    def to_dict(self):
        # This method dumps all object properties, including sensitive ones.
        return self.__dict__

@app.route("/api/users/<int:user_id>")
def get_user(user_id):
    user = find_user_by_id(user_id) # Imagine this retrieves a User object.
    if not user:
        return jsonify({"error": "User not found"}), 404

    # The entire object is serialized and returned, exposing password_hash, ssn, etc.
    return jsonify(user.to_dict())

GOOD Code Example

# SECURE: Use a Data Transfer Object (DTO) to explicitly define the API response structure.
from flask import jsonify

class User: # Same User class as before
    # ...
    pass

class UserPublicDTO:
    def __init__(self, id, username):
        self.id = id
        self.username = username

    @staticmethod
    def from_model(user):
        return UserPublicDTO(id=user.id, username=user.username)

@app.route("/api/users/<int:user_id>")
def get_user(user_id):
    user = find_user_by_id(user_id)
    if not user:
        return jsonify({"error": "User not found"}), 404

    # The User object is transformed into a safe DTO.
    # Only the `id` and `username` fields are included in the response.
    user_dto = UserPublicDTO.from_model(user)
    return jsonify(user_dto.__dict__)

Language-Specific Implementations

JavaScript/TypeScript (NestJS):

// VULNERABLE: Returning raw entity
@Get(':id')
async getUser(@Param('id') id: string) {
  const user = await this.userRepository.findOne(id);
  return user; // Exposes all fields including passwordHash, ssn
}

// SECURE: Use class-transformer with explicit @Expose decorators
import { Expose } from 'class-transformer';

export class UserPublicDto {
  @Expose()
  id: number;

  @Expose()
  username: string;

  // password, ssn, etc. not decorated - won't serialize
}

@Get(':id')
async getUser(@Param('id') id: string) {
  const user = await this.userRepository.findOne(id);
  return plainToClass(UserPublicDto, user, { excludeExtraneousValues: true });
}

Java (Spring Boot):

// VULNERABLE: Returning raw JPA entity
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
    return userRepository.findById(id).orElseThrow();
    // Exposes all fields including passwordHash, ssn
}

// SECURE: Use @JsonView to control serialization
public class Views {
    public static class Public {}
    public static class Internal extends Public {}
}

@Entity
public class User {
    @JsonView(Views.Public.class)
    private Long id;

    @JsonView(Views.Public.class)
    private String username;

    // No @JsonView - won't serialize in public view
    private String passwordHash;
    private String ssn;
}

@GetMapping("/users/{id}")
@JsonView(Views.Public.class)
public User getUser(@PathVariable Long id) {
    return userRepository.findById(id).orElseThrow();
}

C# (ASP.NET Core):

// VULNERABLE: Returning raw entity model
[HttpGet("{id}")]
public ActionResult<User> GetUser(int id)
{
    var user = _context.Users.Find(id);
    return user; // Exposes PasswordHash, Ssn, etc.
}

// SECURE: Use DTOs with AutoMapper or manual mapping
public class UserPublicDto
{
    public int Id { get; set; }
    public string Username { get; set; }
    // No PasswordHash, Ssn, etc.
}

[HttpGet("{id}")]
public ActionResult<UserPublicDto> GetUser(int id)
{
    var user = _context.Users.Find(id);
    if (user == null) return NotFound();

    return new UserPublicDto
    {
        Id = user.Id,
        Username = user.Username
    };
}

Detection

  • Review API responses: Use Burp Suite or OWASP ZAP to intercept API calls. Identify endpoints returning unused, internal, or sensitive fields (e.g., passwordHash, ssn, internalNotes).
  • Analyze database queries: Grep for SELECT * queries feeding API responses.
  • Inspect serialization logic: Find generic .toJSON() or serialize() methods dumping all object properties without filtering.

Prevention

  • Use Data Transfer Objects (DTOs) or ViewModels with an explicit allowlist of fields for every API response.
  • Never return raw database or ORM objects directly from an API endpoint.
  • Select only the required columns in your database queries (SELECT id, username FROM ... instead of SELECT *).
  • Implement field-level authorization based on the user's permissions. For example, a user might see their own email address, but other users cannot.
  • Filter on the server, not the client. Never rely on the client-side application to filter out sensitive data.
  • Define different DTOs for different access levels (e.g., a UserPublicDTO for public profiles and a UserPrivateDTO for a user viewing their own data).

Related Security Patterns & Anti-Patterns

References

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Security

missing-security-headers-anti-pattern

No summary provided by upstream source.

Repository SourceNeeds Review
Security

content-security-policy

No summary provided by upstream source.

Repository SourceNeeds Review
Security

oauth-security-anti-pattern

No summary provided by upstream source.

Repository SourceNeeds Review