CA2119: Seal methods that satisfy private interfaces

Note

This article applies to Visual Studio 2015. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here

Item Value
TypeName SealMethodsThatSatisfyPrivateInterfaces
CheckId CA2119
Category Microsoft.Security
Breaking Change Breaking

Cause

An inheritable public type provides an overridable method implementation of an internal (Friend in Visual Basic) interface.

Rule Description

Interface methods have public accessibility, which cannot be changed by the implementing type. An internal interface creates a contract that is not intended to be implemented outside the assembly that defines the interface. A public type that implements a method of an internal interface using the virtual (Overridable in Visual Basic) modifier allows the method to be overridden by a derived type that is outside the assembly. If a second type in the defining assembly calls the method and expects an internal-only contract, behavior might be compromised when, instead, the overridden method in the outside assembly is executed. This creates a security vulnerability.

How to Fix Violations

To fix a violation of this rule, prevent the method from being overridden outside the assembly by using one of the following:

  • Make the declaring type sealed (NotInheritable in Visual Basic).

  • Change the accessibility of the declaring type to internal (Friend in Visual Basic).

  • Remove all public constructors from the declaring type.

  • Implement the method without using the virtual modifier.

  • Implement the method explicitly.

When to Suppress Warnings

It is safe to suppress a warning from this rule if, after careful review, no security issues exist that might be exploitable if the method is overridden outside the assembly.

Example

The following example shows a type, BaseImplementation, that violates this rule.

using namespace System;

namespace SecurityLibrary
{
   // Internal by default.
   interface class IValidate
   {
      bool UserIsValidated();
   };

   public ref class BaseImplementation : public IValidate
   {
   public:
      virtual bool UserIsValidated()
      {
         return false;
      }
   };

   public ref class UseBaseImplementation
   {
   public:
      void SecurityDecision(BaseImplementation^ someImplementation)
      {
         if(someImplementation->UserIsValidated() == true)
         {
            Console::WriteLine("Account number & balance.");
         }
         else
         {
            Console::WriteLine("Please login.");
         }
      }
   };
}
using System;

namespace SecurityLibrary
{
   // Internal by default.
   interface IValidate
   {
      bool UserIsValidated();
   }

   public class BaseImplementation : IValidate
   {
      public virtual bool UserIsValidated()
      {
         return false;
      }
   }

   public class UseBaseImplementation
   {
      public void SecurityDecision(BaseImplementation someImplementation)
      {
         if(someImplementation.UserIsValidated() == true)
         {
            Console.WriteLine("Account number & balance.");
         }
         else
         {
            Console.WriteLine("Please login.");
         }
      }
   }
}
Imports System

Namespace SecurityLibrary

   Interface IValidate
      Function UserIsValidated() As Boolean
   End Interface

   Public Class BaseImplementation
      Implements IValidate
   
      Overridable Function UserIsValidated() As Boolean _ 
         Implements IValidate.UserIsValidated
         Return False
      End Function

   End Class

   Public Class UseBaseImplementation
   
      Sub SecurityDecision(someImplementation As BaseImplementation)

         If(someImplementation.UserIsValidated() = True)
            Console.WriteLine("Account number & balance.")
         Else
            Console.WriteLine("Please login.")
         End If

      End Sub
   
   End Class

End Namespace

Example

The following example exploits the virtual method implementation of the previous example.

using namespace System;

namespace SecurityLibrary
{
   public ref class BaseImplementation
   {
   public:
      virtual bool UserIsValidated()
      {
         return false;
      }
   };

   public ref class UseBaseImplementation
   {
   public:
      void SecurityDecision(BaseImplementation^ someImplementation)
      {
         if(someImplementation->UserIsValidated() == true)
         {
            Console::WriteLine("Account number & balance.");
         }
         else
         {
            Console::WriteLine("Please login.");
         }
      }
   };
}
using System;

namespace SecurityLibrary
{
    public class BaseImplementation 
    {
        public virtual bool UserIsValidated()
        {
            return false;
        }
    }

    public class UseBaseImplementation
    {
        public void SecurityDecision(BaseImplementation someImplementation)
        {
            if (someImplementation.UserIsValidated() == true)
            {
                Console.WriteLine("Account number & balance.");
            }
            else
            {
                Console.WriteLine("Please login.");
            }
        }
    }
}
Imports System

Namespace SecurityLibrary

   Public Class BaseImplementation
   
      Overridable Function UserIsValidated() As Boolean
         Return False
      End Function

   End Class

   Public Class UseBaseImplementation
   
      Sub SecurityDecision(someImplementation As BaseImplementation)

         If(someImplementation.UserIsValidated() = True)
            Console.WriteLine("Account number & balance.")
         Else
            Console.WriteLine("Please login.")
         End If

      End Sub
   
   End Class

End Namespace

See Also

Interfaces Interfaces