CWE-242: Use of Inherently Dangerous Function
Overview
Some library functions have no safe way to call them - not "easy to misuse," but structurally incapable of operating safely. gets() is the textbook case: it reads a line into a caller-supplied buffer with no argument for the buffer's size, so nothing the caller does before or around the call can stop it from writing past the end of that buffer.
MITRE lists C and C++ under Applicable Platforms - home to gets() and unbounded stream extraction into a character buffer - and that is where scanners raise this finding most often. The definition is not confined to them: Java documented Thread.stop() and System.runFinalizersOnExit() as inherently unsafe before removing them, .NET dropped the BinaryFormatter implementation in .NET 9 on the grounds that it could not be made secure, and Python 2's input() evaluated whatever it read. In each case there is no correct way to call the function, only a different mechanism to use instead.
Outside C and C++, though, the platform has usually withdrawn the function rather than leaving callers to avoid it. Thread.suspend() and Thread.resume() were removed in JDK 23, and Thread.stop(), which threw UnsupportedOperationException from JDK 20 onwards, was removed in JDK 26; on the releases that removed them the call no longer compiles at all, and already-compiled bytecode fails with NoSuchMethodError rather than UnsupportedOperationException. System.runFinalizersOnExit() was removed in Java 11. BinaryFormatter is a different shape of withdrawal: .NET 9 removed the implementation but kept the type, so it still compiles and still constructs, and Serialize/Deserialize throw PlatformNotSupportedException - unless the project references the unsupported System.Runtime.Serialization.Formatters compatibility package, which restores the working implementation and the vulnerability along with it.
So on a managed platform, check the runtime version and the package references before planning a rewrite: if the call already fails on contact, the work is an upgrade rather than a redesign. A live BinaryFormatter finding on .NET 9 or later is precisely the case where it has not failed on contact, so check for that compatibility package before concluding the finding is dead. C and C++ are where these functions still compile and still run, which is why the concrete guidance here is written for them.
Relationship to Other CWEs
These three "dangerous function" CWEs are easy to confuse. The distinction is whether a safe calling convention exists at all:
- CWE-242 (this page) - covers functions with no safe calling convention at all, such as
gets(), where the only fix is to call a different mechanism instead. - CWE-676 (Use of Potentially Dangerous Function) - covers functions such as
strcpy(),sprintf()andsystem()that do have a documented safe calling convention, where the risk is a caller skipping the check the function itself doesn't enforce. CWE-242 covers functions where no safe convention exists, no matter how carefully the caller uses them. - CWE-477 (Use of Obsolete Function) - covers functions the platform has superseded or removed, which is a question of standardization status rather than whether a safe calling convention ever existed. The two can overlap -
gets()is both inherently dangerous (CWE-242) and formally obsolete, having been removed from the C11 standard entirely (CWE-477) - but a function can be one without the other.
OWASP Classification
A06:2025 - Insecure Design
Risk
High: Calling a function with no safe usage pattern produces the same outcome regardless of how carefully the surrounding code is written - typically a buffer overflow that can lead to a crash or arbitrary code execution. Because no amount of caller discipline fixes it, this class of function needs to be banned outright rather than "used carefully."
Remediation Steps
Core Principle: Ban known-unsafe functions outright and replace them with an alternative that takes the information it needs to stay safe - a destination size, a length limit - as part of its own signature.
Trace the Data Path
- Source: Any call to a function on the language's list of inherently dangerous or prohibited functions.
- Sink: The buffer, thread, or object graph the function acts on with no way for the caller to bound what it does there.
- Missing control: No parameter in the function's signature for the caller to supply the limit the function needs, so no validation performed before the call can make it safe.
Replace With a Function That Takes the Missing Constraint (Primary Defense)
// SECURE - pseudo-code
read_bounded(buffer, buffer_capacity, input_stream) // capacity is a required argument
The replacement takes the destination's capacity as a required argument, so no call site can write past the end of the buffer. This differs from adding a bounds check around the same function, because the safety property becomes part of the function's contract instead of the caller's responsibility. Where no bounded equivalent exists, as with a thread-killing or arbitrary-deserialization API, the replacement is a different mechanism rather than a safer call: cooperative cancellation the target code checks, or a serializer with an explicit schema.
Enforce the Ban With Tooling
Add the function to a compiler-enforced or static-analysis-enforced deny list (a "banned function" header, a linter rule) so a reintroduced call fails the build, rather than depending on manual review to catch it.
Test with Malicious Inputs
- Input longer than any fixed-size destination buffer, to confirm the replacement truncates or rejects it rather than overflowing.
- Re-scan or re-run static analysis to confirm no calls to the banned function remain anywhere in the codebase.
Identifying the Category
The test is whether the function's signature can carry the information it needs to stay safe. If it writes into caller-supplied memory with no size parameter, or performs an unbounded action with no way to constrain it, no call site can be made safe and the call has to be replaced. If a documented safe convention exists and the call simply skips it, the finding is CWE-676 instead and the fix is to supply the bound rather than to replace the function.
Common Pitfalls
- Wrapping the dangerous function in a size check instead of replacing it: validating that the expected input "shouldn't" exceed some length doesn't change what the function does if that assumption is ever wrong - it still has no way to stop at the boundary.
- Banning the function in new code but leaving existing calls in place: a lint rule or compiler warning that only fires on new lines doesn't remove the risk from code already shipping; the deny-list has to be enforced against the whole codebase, not just future commits.
- Treating a "mostly safe" wrapper as equivalent to the real fix: a helper that calls the dangerous function internally and hopes its own caller always passes a small enough value just moves the unenforced assumption up one layer instead of removing it.
Language-Specific Guidance
- C -
gets(), unboundedoperator>>extraction into a character buffer in C++, and their bounded replacements