Memory-Safe Doesn't Mean Rust-Only: Go, Java, C#, Swift, and Your Existing Stack

There’s a misconception in some of the memory safety discussion that “memory-safe” equals “Rust.” It doesn’t.

The NSA’s list of memory-safe languages includes: Rust, C#, Go, Java, Ruby, Swift, Python, and JavaScript.

If you’re running a modern tech stack, you’re likely already using memory-safe languages for most of your code. The question is: what about the parts that aren’t?

The Language Decision Matrix

Already Using Java/C#/.NET?
You’re already memory-safe for that code. Focus on identifying any C/C++ dependencies or native extensions.

Already Using Go?
Same story. Go’s garbage collector handles memory management. Your roadmap might already be mostly complete.

Already Using Python/JavaScript?
The language itself is memory-safe. Watch out for native extensions (NumPy’s C core, Node.js addons, etc.).

Have Systems Code in C/C++?
This is where Rust becomes relevant - when you need manual memory management for performance but want safety guarantees.

When Rust vs Other Memory-Safe Languages

Choose Rust When:

  • You need C/C++ level performance
  • You’re replacing existing C/C++ code
  • You need predictable latency (no GC pauses)
  • You’re building systems software, embedded, or kernel code

Choose Go When:

  • You’re building networked services
  • Simplicity and fast development matter
  • GC pauses are acceptable
  • Team productivity is prioritized over micro-optimization

Keep Java/C# When:

  • You have existing investment and expertise
  • Your performance requirements are met
  • The ecosystem and tooling serve your needs

The “Hidden C” Problem

Even if your application code is Python or Java, you might have C/C++ in:

  • Native extensions - Image processing, ML libraries, crypto
  • Database clients - Native protocol implementations
  • FFI calls - Calling into system libraries
  • Build tools - Compilers, bundlers, etc.

Your memory safety roadmap should identify these dependencies and assess their risk.

The Pragmatic Approach

  1. Inventory your codebase by language
  2. Identify C/C++ components and native dependencies
  3. Risk-assess based on attack surface exposure
  4. Plan migration or isolation for high-risk components
  5. Default to memory-safe languages for new code

For most organizations, this isn’t a massive Rust rewrite. It’s identifying the 5-10% of code that needs attention.

Alex’s point about “hidden C” is particularly relevant for data and ML teams.

The Python Paradox

Python is memory-safe. But almost everything that makes Python fast for data work is written in C:

  • NumPy - The core is C and Fortran
  • Pandas - Built on NumPy
  • PyTorch/TensorFlow - C++ cores with Python bindings
  • SciPy - C, C++, and Fortran
  • OpenCV - C++ library
  • scikit-learn - Cython and C

When you import these libraries, you’re running C/C++ code with all its memory safety implications.

Does This Matter for Compliance?

It depends on your threat model and regulatory context:

If you’re processing untrusted input:
A malformed image processed by OpenCV or a crafted tensor passed to PyTorch could trigger memory bugs in the underlying C/C++ code.

If you’re running in a sandbox:
Containerized ML inference with limited privileges has a smaller blast radius.

If you’re just doing internal analytics:
The risk profile is different than internet-facing services.

The Practical Assessment

For ML teams thinking about memory safety roadmaps:

  1. Identify your C/C++ dependencies - pip show <package> often reveals the implementation language
  2. Assess input sources - Does untrusted data touch these libraries?
  3. Evaluate alternatives - Some Rust-based ML libraries exist (but the ecosystem is immature)
  4. Consider isolation - Sandboxing, process separation, capability restrictions

The Honest Answer

For most data teams, replacing the NumPy/PyTorch stack isn’t realistic in any timeline. The CISA guidance acknowledges this:

“A balanced approach acknowledges that MSLs are not a panacea and that transitioning involves significant challenges, particularly for organizations with large existing codebases.”

Document the dependencies, assess the risk, implement mitigations, and track upstream security patches. That’s a defensible position.

The enterprise Java perspective is relevant here because many large organizations already have significant Java investment.

Java’s Memory Safety Position

Java has been memory-safe since 1995. The JVM handles:

  • Automatic memory allocation and garbage collection
  • Array bounds checking
  • Null pointer safety (exceptions, not undefined behavior)
  • Type safety enforcement

For compliance purposes, Java applications are memory-safe by default.

The JNI Caveat

The exception is Java Native Interface (JNI) - when Java code calls into C/C++ libraries:

  • Database drivers with native components
  • Performance-critical operations
  • Platform-specific integrations
  • Legacy library bindings

These JNI boundaries need examination in your memory safety assessment.

What This Means for Compliance

If your stack is primarily Java:

  1. Audit JNI usage - Where does Java call native code?
  2. Assess risk - Are those native calls in security-sensitive paths?
  3. Consider alternatives - Pure Java implementations may exist
  4. Document justification - If native code is necessary, explain why

The Enterprise Java Advantage

Organizations with Java-heavy stacks actually have an easier compliance story:

  • “Our business logic is written in memory-safe Java”
  • “Native dependencies are limited to X, Y, Z with documented risk assessment”
  • “New development defaults to Java/Kotlin with pure-Java libraries where possible”

That’s a credible memory safety roadmap without a major technology shift.

The Modernization Opportunity

For teams considering Kotlin - it’s also memory-safe (runs on JVM) and offers modern language features while maintaining Java interoperability. It’s another path forward within the existing ecosystem.

Alex’s framework is helpful. Let me add the security trade-off perspective across different memory-safe languages.

Memory Safety Is Not the Only Security Property

All the NSA-listed languages prevent memory corruption. But they differ in other security-relevant properties:

Type Safety Strength

  • Rust, Java, C#: Strong static typing catches errors at compile time
  • Python, JavaScript, Ruby: Dynamic typing - more runtime errors possible
  • Go: Moderate - has some dynamic elements

Concurrency Safety

  • Rust: Compile-time data race prevention
  • Go: Runtime race detection, but races are possible
  • Java: Thread-safe constructs, but requires discipline
  • Python: GIL limits true concurrency anyway

Null Safety

  • Rust: No null (uses Option type)
  • Kotlin, Swift: Null-safe by default
  • Java, Go: Nullable references, null pointer exceptions possible

The Security Hierarchy

From a security posture perspective, I’d roughly rank:

  1. Rust - Memory-safe + data race-safe + null-safe
  2. Java/C#/Go - Memory-safe, other guarantees vary
  3. Python/JavaScript/Ruby - Memory-safe but dynamic typing introduces different risks

This doesn’t mean “use Rust for everything.” It means understand what each language prevents and what it doesn’t.

The Audit Conversation

When security reviewers ask about memory safety:

  • “We use Java” is a good answer for memory safety specifically
  • But then they might ask about null pointer exceptions, thread safety, dependency management

Memory safety is one vulnerability class. A comprehensive security posture considers the full picture.

Practical Recommendation

For the CISA roadmap specifically, focus on memory safety - that’s what they’re asking about. But use this as an opportunity to assess your broader language security posture.

Different vulnerability classes, different mitigations. Memory safety is just the one getting government attention right now.