Class with Excessively Deep Inheritance
Description
Class with Excessively Deep Inheritance occurs when a class has an inheritance hierarchy that is too deep, meaning it extends through too many parent classes. CISQ recommends a maximum threshold of 7 parent classes. Deep inheritance hierarchies create fragile base class problems, make code difficult to understand and maintain, and violate the principle of composition over inheritance. When a class inherits from many levels of parents, changes to any ancestor class can have unexpected ripple effects throughout the hierarchy.
Risk
While primarily a maintainability issue, deep inheritance has indirect security implications. Complex hierarchies make security auditing more difficult as behavior is scattered across many classes. The fragile base class problem means security fixes in parent classes may break child class behavior. Understanding the complete behavior of a deeply inherited class requires examining all ancestor classes, making it easy to miss security vulnerabilities. Method overriding across many levels can lead to unexpected behavior. Security controls implemented in parent classes may be inadvertently bypassed by child classes.
Solution
Prefer composition over inheritance - use contained objects instead of extending base classes. Apply the principle of shallow hierarchies (CISQ recommends max 7 levels). Use interfaces instead of abstract base classes where possible. Consider the decorator pattern for adding functionality. Refactor deep hierarchies by extracting common functionality into composition. Use mixins or traits in languages that support them. Apply the single responsibility principle to each class. Review inheritance hierarchies during code reviews with attention to depth.
Common Consequences
| Impact | Details |
|---|---|
| Other | Scope: Other Reduce Maintainability - Deep hierarchies are hard to understand and modify safely. |
| Other | Scope: Other Increase Analytical Complexity - Security analysis must trace through many ancestor classes. |
| Other | Scope: Other Quality Degradation - The fragile base class problem makes changes risky. |
Example Code
Vulnerable Code
// Vulnerable: Excessively deep inheritance (8 levels)
public class Entity {
protected Long id;
}
public class NamedEntity extends Entity {
protected String name;
}
public class TimestampedEntity extends NamedEntity {
protected LocalDateTime createdAt;
protected LocalDateTime updatedAt;
}
public class AuditableEntity extends TimestampedEntity {
protected String createdBy;
protected String modifiedBy;
}
public class VersionedEntity extends AuditableEntity {
protected Long version;
}
public class ApprovedEntity extends VersionedEntity {
protected boolean approved;
protected String approvedBy;
}
public class PublishableEntity extends ApprovedEntity {
protected boolean published;
protected LocalDateTime publishedAt;
}
// Level 8 - Exceeds CISQ threshold of 7
public class BlogPost extends PublishableEntity {
private String title;
private String content;
private List<String> tags;
// To understand BlogPost, you must understand:
// Entity -> NamedEntity -> TimestampedEntity -> AuditableEntity
// -> VersionedEntity -> ApprovedEntity -> PublishableEntity -> BlogPost
//
// Changes to any parent can break this class!
}
# Vulnerable: Deep inheritance chain in Python
class Base:
pass
class Level1(Base):
def process(self):
return "Level1"
class Level2(Level1):
def process(self):
return super().process() + " -> Level2"
class Level3(Level2):
def process(self):
return super().process() + " -> Level3"
class Level4(Level3):
def process(self):
return super().process() + " -> Level4"
class Level5(Level4):
def process(self):
return super().process() + " -> Level5"
class Level6(Level5):
def process(self):
return super().process() + " -> Level6"
class Level7(Level6):
def process(self):
return super().process() + " -> Level7"
class Level8(Level7): # Exceeds threshold
def process(self):
return super().process() + " -> Level8"
# To understand Level8.process(), must trace through 8 classes!
# Method Resolution Order (MRO) becomes very complex
// Vulnerable: Deep inheritance in C#
public class BaseController { }
public class AuthenticatedController : BaseController
{
protected bool IsAuthenticated { get; set; }
}
public class AuthorizedController : AuthenticatedController
{
protected List<string> Permissions { get; set; }
}
public class LoggingController : AuthorizedController
{
protected ILogger Logger { get; set; }
}
public class CachingController : LoggingController
{
protected ICache Cache { get; set; }
}
public class TransactionalController : CachingController
{
protected ITransaction Transaction { get; set; }
}
public class AuditingController : TransactionalController
{
protected IAuditLog AuditLog { get; set; }
}
// Level 8 - Too deep
public class OrderController : AuditingController
{
// Inherits: BaseController -> AuthenticatedController ->
// AuthorizedController -> LoggingController -> CachingController ->
// TransactionalController -> AuditingController -> OrderController
//
// Finding which method actually executes is very difficult!
}
Fixed Code
// Fixed: Composition over inheritance
// Instead of deep hierarchy, use composition and interfaces
public interface Identifiable {
Long getId();
}
public interface Named {
String getName();
}
public interface Timestamped {
LocalDateTime getCreatedAt();
LocalDateTime getUpdatedAt();
}
public interface Auditable {
String getCreatedBy();
String getModifiedBy();
}
public interface Versioned {
Long getVersion();
}
public interface Approvable {
boolean isApproved();
String getApprovedBy();
}
public interface Publishable {
boolean isPublished();
LocalDateTime getPublishedAt();
}
// Fixed: Single-level inheritance with composition
public class BlogPost extends Entity implements
Named, Timestamped, Auditable, Versioned, Approvable, Publishable {
private String name;
private String title;
private String content;
private List<String> tags;
// Composition: delegate to helper objects
private final TimestampInfo timestamps = new TimestampInfo();
private final AuditInfo audit = new AuditInfo();
private final VersionInfo version = new VersionInfo();
private final ApprovalInfo approval = new ApprovalInfo();
private final PublishInfo publish = new PublishInfo();
@Override
public String getName() { return name; }
@Override
public LocalDateTime getCreatedAt() { return timestamps.getCreatedAt(); }
@Override
public LocalDateTime getUpdatedAt() { return timestamps.getUpdatedAt(); }
@Override
public String getCreatedBy() { return audit.getCreatedBy(); }
@Override
public String getModifiedBy() { return audit.getModifiedBy(); }
@Override
public Long getVersion() { return version.getVersion(); }
@Override
public boolean isApproved() { return approval.isApproved(); }
@Override
public String getApprovedBy() { return approval.getApprovedBy(); }
@Override
public boolean isPublished() { return publish.isPublished(); }
@Override
public LocalDateTime getPublishedAt() { return publish.getPublishedAt(); }
}
// Helper classes are simple, focused, and reusable
@Embeddable
public class TimestampInfo {
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
// getters, setters
}
@Embeddable
public class AuditInfo {
private String createdBy;
private String modifiedBy;
// getters, setters
}
# Fixed: Mixins and composition instead of deep inheritance
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional, List
# Mixins for shared functionality (shallow, focused)
class ProcessingMixin:
def process(self):
raise NotImplementedError
class LoggingMixin:
def log(self, message):
print(f"[{datetime.now()}] {message}")
class ValidationMixin:
def validate(self):
pass # Override in concrete class
# Composition helpers
@dataclass
class TimestampData:
created_at: datetime = field(default_factory=datetime.now)
updated_at: Optional[datetime] = None
@dataclass
class AuditData:
created_by: str = ""
modified_by: str = ""
@dataclass
class VersionData:
version: int = 1
# Fixed: Flat class using composition and mixins
@dataclass
class BlogPost(ProcessingMixin, LoggingMixin, ValidationMixin):
"""Blog post using composition instead of deep inheritance."""
id: int
title: str
content: str
tags: List[str] = field(default_factory=list)
# Composition instead of inheritance
timestamps: TimestampData = field(default_factory=TimestampData)
audit: AuditData = field(default_factory=AuditData)
version: VersionData = field(default_factory=VersionData)
published: bool = False
approved: bool = False
def process(self):
self.log(f"Processing post: {self.title}")
self.validate()
return f"Processed: {self.title}"
def validate(self):
if not self.title:
raise ValueError("Title required")
if not self.content:
raise ValueError("Content required")
def publish(self, publisher: str):
if not self.approved:
raise PermissionError("Post must be approved before publishing")
self.published = True
self.timestamps.updated_at = datetime.now()
self.audit.modified_by = publisher
# Maximum inheritance depth: 1 (object -> BlogPost)
# Functionality added via mixins and composition
// Fixed: Decorator pattern and composition
// Instead of deep controller hierarchy, use filters and middleware
public interface IController
{
Task<IActionResult> Execute(ControllerContext context);
}
// Simple base controller
public abstract class BaseController : IController
{
public abstract Task<IActionResult> Execute(ControllerContext context);
}
// Fixed: Use attributes/filters instead of inheritance
[Authenticate]
[Authorize("OrderManagement")]
[Log]
[Cache(Duration = 60)]
[Transactional]
[Audit]
public class OrderController : BaseController
{
private readonly IOrderService _orderService;
private readonly ILogger<OrderController> _logger;
public OrderController(IOrderService orderService, ILogger<OrderController> logger)
{
_orderService = orderService;
_logger = logger;
}
public override async Task<IActionResult> Execute(ControllerContext context)
{
// Focused controller logic - cross-cutting concerns handled by filters
var order = await _orderService.GetOrderAsync(context.OrderId);
return new OkResult(order);
}
}
// Cross-cutting concerns as separate filter classes
public class AuthenticateAttribute : ActionFilterAttribute
{
public override async Task OnActionExecutionAsync(
ActionExecutingContext context, ActionExecutionDelegate next)
{
if (!context.HttpContext.User.Identity.IsAuthenticated)
{
context.Result = new UnauthorizedResult();
return;
}
await next();
}
}
public class LogAttribute : ActionFilterAttribute
{
public override async Task OnActionExecutionAsync(
ActionExecutingContext context, ActionExecutionDelegate next)
{
var logger = context.HttpContext.RequestServices.GetService<ILogger>();
logger.LogInformation("Executing {Action}", context.ActionDescriptor.DisplayName);
await next();
logger.LogInformation("Executed {Action}", context.ActionDescriptor.DisplayName);
}
}
// Alternative: Use decorator pattern
public class LoggingControllerDecorator : IController
{
private readonly IController _inner;
private readonly ILogger _logger;
public LoggingControllerDecorator(IController inner, ILogger logger)
{
_inner = inner;
_logger = logger;
}
public async Task<IActionResult> Execute(ControllerContext context)
{
_logger.LogInformation("Before execution");
var result = await _inner.Execute(context);
_logger.LogInformation("After execution");
return result;
}
}
CVE Examples
This CWE is marked as PROHIBITED for direct CVE mapping as it represents a code quality/maintainability concern rather than a direct security vulnerability.
Related CWEs
- CWE-1093: Excessively Complex Data Representation (parent)
- CWE-1055: Multiple Inheritance from Concrete Classes (related)
- CWE-1226: Complexity Issues (category member)
References
- MITRE Corporation. "CWE-1074: Class with Excessively Deep Inheritance." https://cwe.mitre.org/data/definitions/1074.html
- CISQ. "Automated Source Code Quality Measures."
- Gamma, Erich et al. "Design Patterns" - Favor composition over inheritance.