Skip to content

CWE-1105: Insufficient Encapsulation of Machine-Dependent Functionality

Overview

Machine-dependent functionality - pointer width, byte order (endianness), memory alignment requirements, and CPU-specific instruction sets - behaves differently across architectures. When code relies on these characteristics directly instead of isolating them behind a portable interface, the assumption silently breaks on a different platform: a pointer truncates, a value is misread because the byte order was assumed rather than checked, an unaligned access faults, or code compiled for one instruction set crashes or misbehaves on another.

Relationship to Other CWEs

MITRE's mapping guidance for CWE-1105 is Prohibited. The entry "is primarily a quality issue with no direct security implications", and the note tells you to "look for weaknesses that are focused specifically on insecure behaviors that have more direct security implications". So a finding should not be filed under this number - a statement about the number, not about the code. The failures below are real, and each has a CWE that names the consequence rather than the portability defect that produced it.

Where it sits in Research Concepts (view-1000): ChildOf CWE-758 (Reliance on Undefined, Unspecified, or Implementation-Defined Behavior) and CWE-1061 (Insufficient Encapsulation); its one child there is CWE-188 (Reliance on Data/Memory Layout); PeerOf CWE-1102 (Reliance on Machine-Dependent Data Representation). None of those four has a page here.

What to file instead, by which pattern below produced the finding:

  • A pointer truncated into a narrower integer - CWE-197 (Numeric Truncation Error) for the lost bits themselves. Where the truncated value is then used as an address or a size, the memory-safety CWE for what it reaches is the more useful number: CWE-787 or CWE-125.
  • Raw memory reinterpreted as a multi-byte value - CWE-188 (Reliance on Data/Memory Layout) for the layout assumption, or CWE-1102 where the specific assumption is byte order. If the misread value is a length or offset that then drives a read or write past the object, file that: CWE-125 or CWE-787.
  • A hardware capability assumed rather than handled - the defect is a variable left unassigned on the branch nobody wrote, which is CWE-457 (Use of Uninitialized Variable); it has no page here.

Use this page as the remediation reference once the number is settled, not as the number.

OWASP Classification

A10:2025 - Mishandling of Exceptional Conditions

Risk

Medium-High: The consequence depends on which assumption breaks. A truncated pointer corrupts memory on 64-bit systems. A byte order assumed rather than checked corrupts protocol and file-format data. An unaligned access faults on the architectures that require alignment, which is a denial of service. And a CPU feature that turns out to be absent leaves execution on a path nobody wrote, where the security operation it was meant to perform produces no result and no error.

Remediation Steps

Core Principle: Keep machine-dependent assumptions - pointer size, byte order, alignment, available instructions - out of general code. Isolate them behind one portable interface, and verify them rather than assuming them.

Trace the Data Path

  • Source: Code that assumes a specific pointer width, byte order, memory alignment, or CPU instruction set is present.
  • Sink: The memory access, arithmetic operation, or serialized data format that depends on that assumption being true.
  • Data Flow / Missing Controls: No explicit, fixed-width type, no explicit byte-order conversion, no alignment-safe access pattern, and no runtime check before using a platform- or CPU-specific capability.

Use Explicit, Fixed-Width Types Instead of Assumed Sizes (Primary Defense)

  • Use fixed-width integer types for anything that must have a specific size (a 32-bit value must stay 32-bit on every platform), instead of a native type whose width varies by architecture.
  • Never cast a pointer to a fixed-size integer type narrower than the platform's actual pointer width; use the language's pointer-sized integer type instead.

Convert Byte Order Explicitly at Every Serialization Boundary

  • Any value written to a file, sent over a network, or shared with another process needs its byte order made explicit at that boundary (network/wire byte order in, host byte order out, and back) rather than being read or written as raw memory.
  • Never reinterpret a byte buffer as a multi-byte integer type directly; unpack it field-by-field or through an explicit byte-order conversion function.

Access Unaligned Data Safely

  • Never read or write a multi-byte value through a pointer cast that isn't guaranteed to be properly aligned for that type; copy the bytes into a properly aligned location first.

Detect CPU Features at Runtime, Not by Assumption

  • Check that an instruction set extension is actually available before using it, and provide a fallback for when it is absent - a missing hardware feature should cost functionality or performance, never security.
  • Centralize architecture-specific branches (#if-style platform guards) in one isolated location instead of scattering them through general application logic, so machine-dependent code has one place to review and test.

Test Across Architectures

  • Run or emulate the code on a different word size and a different byte order than the primary development platform.
  • Force the CPU-feature-detection fallback path and confirm it is both functionally correct and does not silently weaken a security property.
  • Re-run the static/security scanner to confirm the finding is resolved.

Common Vulnerable Patterns

A pointer stored in a narrower integer

// VULNERABLE - pointer truncated into a narrower integer type
handle_as_int = (int32) pointer            // truncates on a 64-bit platform

Why this is vulnerable: the cast is a request, not a question, so nothing objects at compile time and nothing reports a problem at run time - the high half of the address is discarded and what remains is a perfectly well-formed 32-bit integer. Converted back later, it addresses memory that has nothing to do with the original object.

The reason this ships is that it is correct on the machine it was written for. Every 32-bit target behaves exactly as the author expected, and the same source is wrong the moment it is built for a 64-bit one - or, on Windows, wrong for long while remaining right for size_t, since the widths do not move together across platforms. An integer type chosen to hold an address has to be the one the platform defines for that purpose rather than one that happens to be wide enough today.

Raw memory reinterpreted as a multi-byte value

// VULNERABLE - raw memory reinterpreted as a multi-byte value
value = *(uint32*) buffer                  // wrong result if buffer's byte
                                           // order differs from the host's

Why this is vulnerable: this line makes two machine-dependent assumptions at once and neither is stated. It assumes the bytes in buffer are ordered the way this CPU orders them, which is systematically false for anything read off a network, where the convention is the opposite of the host order on most hardware in use. And it assumes buffer is aligned for a four-byte read, which is a property of wherever the buffer came from - on some architectures a misaligned access faults, and on others it silently costs performance or returns a different result.

Neither failure is intermittent, which is what makes it deceptive: the value is wrong the same way every time on the affected platform and right every time on the development one, so the bug reads as "works here, broken there" rather than as a defect in this line. Reading the bytes individually and combining them with an explicit byte order removes both assumptions at once.

A hardware capability assumed rather than handled

// VULNERABLE - hardware feature assumed present, no fallback
if cpu_has_feature("AES-NI"):
    result = hardware_encrypt(data)
// falls through silently with no result if the check ever returns false

Why this is vulnerable: the check is present and the branch it guards is the only branch there is. Where the feature is absent the condition is simply false, result is never assigned, and execution continues - so the failure is not an error but a missing value, which surfaces later as whatever the uninitialised or default result happens to mean to the code that consumes it.

A capability test with no alternative path turns an optimisation into a correctness dependency: the code is written as though the hardware path were a faster way of doing something, when in practice it is the only way anything gets done at all. Either the alternative implementation exists and is selected here, or the absence of the feature is a startup failure. Continuing without either is what produces silent wrong answers.

Secure Patterns

// SECURE - pointer-sized integer type, never truncated
handle_as_int = (pointer_sized_int) pointer

// SECURE - explicit byte-order conversion at the boundary
value = network_to_host_order(read_bytes(buffer, 4))

// SECURE - runtime feature check with a correct, explicit fallback
if cpu_has_feature("AES-NI"):
    result = hardware_encrypt(data)
else:
    result = software_encrypt(data)        // equally correct, just slower

Why this works: A pointer-sized type cannot truncate, whatever the platform it is built for. Converting byte order where the data crosses the boundary means the in-memory representation is never trusted to match the sender's or the file's; it is made correct on the way in and on the way out. A feature check with a real fallback leaves the absence of hardware costing performance rather than correctness or security.

Language-Specific Guidance

  • C - stdint.h fixed-width types, ntohl/htonl byte-order conversion, cpuid-based feature detection, and portable alternatives to architecture-specific inline assembly

Additional Resources