Back to Blog

Attack Surface at StellarBridge

Reducing Attack Surface by Design

One of the most effective ways to manage attack surface is also the simplest: eliminate it. Yet this principle is routinely neglected across the industry. The evidence is everywhere. We see a steady rise in defensive products—web application firewalls, AI firewalls, runtime protection layers, and similar tools. These technologies are not inherently bad, nor are they entirely unnecessary. The problem is how they are consumed by most: as band-aids. Instead of addressing the architectural decisions that create attack surface in the first place, organizations often allow that surface to persist and rely on external services to shield it.

This approach treats symptoms rather than causes.

At Stellarbridge, we chose to take a different path. Not every outcome was planned from day one, but the direction was deliberate. As we designed and built the platform, a consistent theme emerged: meaningful security improvements come from subtraction, not addition. But the equation is not one of simplistic subtraction. You must subtract the right things.

What follows are some of the key lessons we learned along the way.


Language Choice Matters—But Not for the Usual Reasons

Most discussions about programming languages focus on performance, ergonomics, or developer preference. In reality, most modern languages are broadly equivalent abstractions. Each has strengths, each has tradeoffs, and none are inherently "secure" by default.

What matters is not the language itself, but what the language allows—or forces—you to depend on.

From the outset, we knew we did not want to manage traditional Linux virtual machines or Docker containers bloated with system packages, default utilities, and transitive dependencies. Even minimal distributions carry a surprising amount of implicit attack surface that require careful hardening, deliberate system maintenance and hardware requirements.

Our target was more extreme: a container image that was as close to "nothing" as possible.


Designing for a Near-Zero OS Footprint

We standardized on a fully static base image that is only a few megabytes in size and includes essentially no operating system components beyond certificates and basic locality data. There is no package manager. There are no shells. There are no system utilities to exploit.

Running an application in this environment imposes hard constraints:

  • The application must be compiled (e.g., Go, Rust, C/C++).
  • It cannot rely on system-level libraries.
  • All required functionality must be built directly into the binary.
  • Interpreted runtimes (Python, Node.js, JavaScript, TypeScript, etc.) are effectively off the table due to their dependency on external interpreters and system tooling. Though you will see in a minute, we actually do use javascript for our frontend (still coming from our minimal docker container).

Rather than fighting these constraints, we embraced them.


A Single Binary, Intentionally

We selected Go—not a surprising choice—but applied it more aggressively than is typical.

Our primary application serves both the frontend and the API from a single compiled binary. Instead of deploying separate frontend and backend services, configuring networking rules between them, and expanding the attack surface accordingly, we compile the frontend as a static site (built with SvelteKit) and embed it directly into the Go binary at build time.

That binary is then copied into the container image. Nothing else goes in.

The result is straightforward: everything the application needs to run is already inside the executable.


Exceptions, Kept Explicit and Isolated

There are a few deliberate exceptions:

  • A customer-facing API service, written in Go, deployed separately using the same static-image approach.
  • A chain-of-custody engine written in Python, driven by PDF-generation requirements.
  • Authentication handled via a third-party identity provider.

These components are isolated, intentional, and narrowly scoped. Outside of them, the core application—and the controls that protect it—exist entirely within the primary binary.


Security as the Absence of Possibility

Why go to the trouble of using such a restrictive container model?

Because it eliminates entire classes of exploits outright.

  • You cannot upload files into the container.
  • You cannot spawn shells.
  • You cannot exploit vulnerabilities in system-level Linux binaries. They simply do not exist.

These protections are not enforced by runtime agents, policy engines, or defensive overlays. They are enforced by architecture. The attack vectors are absent, not guarded.


Making Exploitation Inconvenient by Design

This does not mean the system is impenetrable. No serious security practitioner believes that. Given enough time, skill, and resources, anything can be compromised.

Our goal is more practical: to make exploitation as inconvenient, constrained, and expensive as possible. By aggressively reducing attack surface at the architectural level, we shift the burden back to the attacker instead of piling complexity onto the defender.

Security does not have to start with more tools. Sometimes, it starts by building less.