VYPR
Moderate severityNVD Advisory· Published Feb 10, 2025· Updated Feb 11, 2025

CVE-2024-42512

CVE-2024-42512

Description

Vulnerability in the OPC UA .NET Standard Stack before 1.5.374.158 allows an unauthorized attacker to bypass application authentication when the deprecated Basic128Rsa15 security policy is enabled.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

OPC UA .NET Standard Stack before 1.5.374.158 allows authentication bypass via the deprecated Basic128Rsa15 security policy, enabling unauthorized access.

Vulnerability

Overview

CVE-2024-42512 is an authentication bypass vulnerability in the OPC UA .NET Standard Stack, affecting versions prior to 1.5.374.158. The flaw is exploitable only when the deprecated Basic128Rsa15 security policy is enabled, which is disabled by default [3][4]. The root cause lies in insufficient validation of client credentials during the handshake, allowing an unauthorized attacker to bypass application authentication. The fix introduces a rogue client detection mechanism at the transport layer to identify and block suspicious activity [1].

Exploitation

An attacker with network access to an OPC UA server that has Basic128Rsa15 enabled can exploit this vulnerability without prior authentication. The attack does not require any special privileges or user interaction. By sending crafted messages, the attacker can impersonate a legitimate client and bypass the authentication checks, gaining unauthorized access to the server's resources [3][4].

Impact

Successful exploitation allows the attacker to perform any operation that an authenticated client could, including reading and writing data, invoking methods, and potentially disrupting industrial processes. Given OPC UA's widespread use in critical infrastructure, this could lead to severe consequences such as data theft, process manipulation, or denial of service [3].

Mitigation

The vulnerability is fixed in version 1.5.374.158 of the OPC UA .NET Standard Stack. Users are strongly advised to update immediately and, if possible, disable the Basic128Rsa15 security policy. The patch includes a detection mechanism that may cause a denial of service when an attack is detected, which is considered an acceptable trade-off to prevent compromise [4]. No workarounds are available other than upgrading or disabling the deprecated policy.

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
OPCFoundation.NetStandard.Opc.Ua.CoreNuGet
< 1.5.374.1581.5.374.158

Affected products

2

Patches

1
3543d0292556

Added a minimal rogue client detection mechanism at the transport level (#2850)

https://github.com/OPCFoundation/UA-.NETStandardSuciu Mircea AdrianNov 22, 2024via ghsa
2 files changed · +278 1
  • Stack/Opc.Ua.Core/Stack/Tcp/TcpListenerChannel.cs+13 0 modified
    @@ -11,6 +11,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     */
     
     using System;
    +using System.Net;
     using System.Net.Sockets;
     using System.Security.Cryptography.X509Certificates;
     using Microsoft.Extensions.Logging;
    @@ -267,6 +268,18 @@ protected void ForceChannelFault(ServiceResult reason)
     
                     if (close)
                     {
    +                    // mark the RemoteAddress as potential problematic if Basic128Rsa15
    +                    if ((SecurityPolicyUri == SecurityPolicies.Basic128Rsa15) &&
    +                        (reason.StatusCode == StatusCodes.BadSecurityChecksFailed || reason.StatusCode == StatusCodes.BadTcpMessageTypeInvalid))
    +                    {
    +                        var tcpTransportListener = m_listener as TcpTransportListener;
    +                        if (tcpTransportListener != null)
    +                        {
    +                            tcpTransportListener.MarkAsPotentialProblematic
    +                                (((IPEndPoint)Socket.RemoteEndpoint).Address);
    +                        }
    +                    }
    +
                         // close channel immediately.
                         ChannelFaulted();
                     }
    
  • Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs+265 1 modified
    @@ -13,6 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     using System;
     using System.Collections.Concurrent;
     using System.Collections.Generic;
    +using System.Diagnostics;
     using System.Linq;
     using System.Net;
     using System.Net.Sockets;
    @@ -37,6 +38,233 @@ public override ITransportListener Create()
             }
         }
     
    +    /// <summary>
    +    /// Represents a potential problematic ActiveClient
    +    /// </summary>
    +    public class ActiveClient
    +    {
    +        #region Properties
    +        /// <summary>
    +        /// Time of the last recorded problematic action
    +        /// </summary>
    +        public int LastActionTicks
    +        {
    +            get
    +            {
    +                return m_lastActionTicks;
    +            }
    +            set
    +            {
    +                m_lastActionTicks = value;
    +            }
    +        }
    +
    +        /// <summary>
    +        /// Counter for number of recorded potential problematic actions
    +        /// </summary>
    +        public int ActiveActionCount
    +        {
    +            get
    +            {
    +                return m_actionCount;
    +            }
    +            set
    +            {
    +                m_actionCount = value;
    +            }
    +        }
    +
    +        /// <summary>
    +        /// Ticks until the client is Blocked
    +        /// </summary>
    +        public int BlockedUntilTicks
    +        {
    +            get
    +            {
    +                return m_blockedUntilTicks;
    +            }
    +            set
    +            {
    +                m_blockedUntilTicks = value;
    +            }
    +        }
    +        #endregion
    +
    +        #region Private members
    +        int m_lastActionTicks;
    +        int m_actionCount;
    +        int m_blockedUntilTicks;
    +        #endregion
    +    }
    +
    +    /// <summary>
    +    /// Manages clients with potential problematic activities
    +    /// </summary>
    +    public class ActiveClientTracker : IDisposable
    +    {
    +        #region Public
    +        /// <summary>
    +        /// Constructor
    +        /// </summary>
    +        public ActiveClientTracker()
    +        {
    +            m_cleanupTimer = new Timer(CleanupExpiredEntries, null, m_kCleanupIntervalMs, m_kCleanupIntervalMs);
    +        }
    +
    +        /// <summary>
    +        /// Checks if an IP address is currently blocked
    +        /// </summary>
    +        /// <param name="ipAddress"></param>
    +        /// <returns></returns>
    +        public bool IsBlocked(IPAddress ipAddress)
    +        {
    +            if (m_activeClients.TryGetValue(ipAddress, out ActiveClient client))
    +            {
    +                int currentTicks = HiResClock.TickCount;
    +                return IsBlockedTicks(client.BlockedUntilTicks, currentTicks);
    +            }
    +            return false;
    +        }
    +
    +        /// <summary>
    +        /// Adds a potential problematic action entry for a client
    +        /// </summary>
    +        /// <param name="ipAddress"></param>
    +        public void AddClientAction(IPAddress ipAddress)
    +        {
    +            int currentTicks = HiResClock.TickCount;
    +
    +            m_activeClients.AddOrUpdate(ipAddress,
    +                // If client is new , create a new entry
    +                key => new ActiveClient {
    +                    LastActionTicks = currentTicks,
    +                    ActiveActionCount = 1,
    +                    BlockedUntilTicks = 0
    +                },
    +                // If the client exists, update its entry
    +                (key, existingEntry) => {
    +                    // If IP currently blocked simply do nothing
    +                    if (IsBlockedTicks(existingEntry.BlockedUntilTicks, currentTicks))
    +                    {
    +                        return existingEntry;
    +                    }
    +
    +                    // Elapsed time since last recorded action
    +                    int elapsedSinceLastRecAction = currentTicks - existingEntry.LastActionTicks;
    +
    +                    if (elapsedSinceLastRecAction <= m_kActionsIntervalMs)
    +                    {
    +                        existingEntry.ActiveActionCount++;
    +
    +                        if (existingEntry.ActiveActionCount > m_kNrActionsTillBlock)
    +                        {
    +                            // Block the IP
    +                            existingEntry.BlockedUntilTicks = currentTicks + m_kBlockDurationMs;
    +                            Utils.LogError("RemoteClient IPAddress: {0} blocked for {1} ms due to exceeding {2} actions under {3} ms ",
    +                                ipAddress.ToString(),
    +                                m_kBlockDurationMs,
    +                                m_kNrActionsTillBlock,
    +                                m_kActionsIntervalMs);
    +
    +                        }
    +                    }
    +                    else
    +                    {
    +                        // Reset the count as the last action was outside the interval
    +                        existingEntry.ActiveActionCount = 1;
    +                    }
    +
    +                    existingEntry.LastActionTicks = currentTicks;
    +
    +                    return existingEntry;
    +                }
    +            );
    +        }
    +
    +        /// <summary>
    +        /// Dispose the cleanup timer
    +        /// </summary>
    +        public void Dispose()
    +        {
    +            m_cleanupTimer?.Dispose();
    +        }
    +
    +        #endregion
    +        #region Private methods
    +
    +        /// <summary>
    +        /// Periodically cleans up expired active client entries to avoid memory leak and unblock clients whose duration has expired.
    +        /// </summary>
    +        /// <param name="state"></param>
    +        private void CleanupExpiredEntries(object state)
    +        {
    +            int currentTicks = HiResClock.TickCount;
    +
    +            foreach (var entry in m_activeClients)
    +            {
    +                IPAddress clientIp = entry.Key;
    +                ActiveClient rClient = entry.Value;
    +
    +                // Unblock client if blocking duration has been exceeded
    +                if (rClient.BlockedUntilTicks != 0 && !IsBlockedTicks(rClient.BlockedUntilTicks, currentTicks))
    +                {
    +                    rClient.BlockedUntilTicks = 0;
    +                    rClient.ActiveActionCount = 0;
    +                    Utils.LogDebug("Active Client with IP {0} is now unblocked, blocking duration of {1} ms has been exceeded",
    +                        clientIp.ToString(),
    +                        m_kBlockDurationMs);
    +                }
    +
    +                // Remove clients that haven't had any potential problematic actions in the last m_kEntryExpirationMs interval 
    +                int elapsedSinceBadActionTicks = currentTicks - rClient.LastActionTicks;
    +                if (elapsedSinceBadActionTicks > m_kEntryExpirationMs)
    +                {
    +                    // Even if TryRemove fails it will most probably succeed at the next execution
    +                    if (m_activeClients.TryRemove(clientIp, out _))
    +                    {
    +                        Utils.LogDebug("Active Client with IP {0} is not tracked any longer, hasn't had actions for more than {1} ms",
    +                            clientIp.ToString(),
    +                            m_kEntryExpirationMs);
    +                    }
    +                }
    +            }
    +        }
    +
    +        /// <summary>
    +        /// Determines if the IP is currently blocked based on the block expiration ticks and current ticks
    +        /// </summary>
    +        /// <param name="blockedUntilTicks"></param>
    +        /// <param name="currentTicks"></param>
    +        /// <returns></returns>
    +        private bool IsBlockedTicks(int blockedUntilTicks, int currentTicks)
    +        {
    +            if (blockedUntilTicks == 0)
    +            {
    +                return false;
    +            }
    +            // C# signed arithmetic 
    +            int diff = blockedUntilTicks - currentTicks;
    +            // If currentTicks < blockedUntilTicks then it is still blocked
    +            // Works even if TickCount has wrapped around due to C# signed integer arithmetic
    +            return diff > 0;
    +        }
    +
    +
    +        #endregion
    +        #region Private members
    +        private ConcurrentDictionary<IPAddress, ActiveClient> m_activeClients = new ConcurrentDictionary<IPAddress, ActiveClient>();
    +
    +        private const int m_kActionsIntervalMs = 10_000;
    +        private const int m_kNrActionsTillBlock = 3;
    +
    +        private const int m_kBlockDurationMs = 30_000; // 30 seconds
    +        private const int m_kCleanupIntervalMs = 15_000;
    +        private const int m_kEntryExpirationMs = 600_000; // 10 minutes
    +
    +        private Timer m_cleanupTimer;
    +        #endregion
    +    }
    +
         /// <summary>
         /// Manages the transport for a UA TCP server.
         /// </summary>
    @@ -331,6 +559,12 @@ public void Start()
             {
                 lock (m_lock)
                 {
    +                // Track potential problematic client behavior only if Basic128Rsa15 security policy is offered
    +                if (m_descriptions != null && m_descriptions.Any(d => d.SecurityPolicyUri == SecurityPolicies.Basic128Rsa15))
    +                {
    +                    m_activeClientTracker = new ActiveClientTracker();
    +                }
    +
                     // ensure a valid port.
                     int port = m_uri.Port;
     
    @@ -505,16 +739,44 @@ public void CertificateUpdate(
             }
             #endregion
     
    +        #region Internal
    +        /// <summary>
    +        /// Mark a remote endpoint as potential problematic
    +        /// </summary>
    +        /// <param name="remoteEndpoint"></param>
    +        internal void MarkAsPotentialProblematic(IPAddress remoteEndpoint)
    +        {
    +            Utils.LogDebug("MarkClientAsPotentialProblematic address: {0} ", remoteEndpoint.ToString());
    +            m_activeClientTracker?.AddClientAction(remoteEndpoint);
    +        }
    +        #endregion
    +
             #region Socket Event Handler
             /// <summary>
             /// Handles a new connection.
             /// </summary>
             private void OnAccept(object sender, SocketAsyncEventArgs e)
             {
    +
                 TcpListenerChannel channel = null;
                 bool repeatAccept = false;
                 do
                 {
    +                bool isBlocked = false;
    +
    +                // Track potential problematic client behavior only if Basic128Rsa15 security policy is offered
    +                if (m_activeClientTracker != null)
    +                {
    +                    // Filter out the Remote IP addresses which are detected with potential problematic behavior
    +                    IPAddress ipAddress = ((IPEndPoint)e?.AcceptSocket?.RemoteEndPoint)?.Address;
    +                    if (ipAddress != null && m_activeClientTracker.IsBlocked(ipAddress))
    +                    {
    +                        Utils.LogDebug("OnAccept: RemoteEndpoint address: {0} refused access for behaving as potential problematic ",
    +                            ((IPEndPoint)e.AcceptSocket.RemoteEndPoint).Address.ToString());
    +                        isBlocked = true;
    +                    }
    +                }
    +
                     repeatAccept = false;
                     lock (m_lock)
                     {
    @@ -526,7 +788,7 @@ private void OnAccept(object sender, SocketAsyncEventArgs e)
                         }
     
                         var channels = m_channels;
    -                    if (channels != null)
    +                    if (channels != null && !isBlocked)
                         {
                             // TODO: .Count is flagged as hotpath, implement separate counter
                             int channelCount = channels.Count;
    @@ -821,6 +1083,8 @@ private void SetUri(Uri baseAddress, string relativeAddress)
             private int m_inactivityDetectPeriod;
             private Timer m_inactivityDetectionTimer;
             private int m_maxChannelCount;
    +
    +        private ActiveClientTracker m_activeClientTracker;
             #endregion
         }
     
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.