AgentStack
SKILL verified MIT Self-run

Excessive Data Exposure Anti Pattern

skill-igbuend-grimbard-excessive-data-exposure-anti-pattern · by igbuend

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.

No reviews yet
0 installs
11 views
0.0% view→install

Install

$ agentstack add skill-igbuend-grimbard-excessive-data-exposure-anti-pattern

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Excessive Data Exposure Anti Pattern? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

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/")
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/")
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 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 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

  • [Missing Authentication Anti-Pattern](../missing-authentication/): If an endpoint is missing authentication, excessive data exposure becomes even more dangerous.
  • [Mass Assignment Anti-Pattern](../mass-assignment/): The inverse of this problem, where an API accepts more data than it should, leading to unauthorized modifications.

References

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.