Software Engineering

The Strangler Pattern, Applied to Security Debt

TuniCyberLabs Team
8 min read

Rewriting a legacy system in one go never gets funded. Here is how to strangle it slice by slice, ordered by attack surface rather than roadmap value, and how to retire the old path without leaving it running.

Security debt is not paid off in a single release. Nobody signs a cheque for an eighteen month rewrite of a system that is currently taking orders, and the teams who try usually ship the same vulnerability classes into a newer framework. The strangler pattern is the third option: put a routing layer in front of the legacy application, move one slice at a time behind it, and let the old system shrink until you can switch it off.

The textbook version of that pattern is driven by features. Applied to security debt it is driven by exposure, and that one change rewrites nearly every decision: which slice goes first, what "done" means, and when you are allowed to delete the old code.

What the strangler pattern is, and why exposure changes the order

You put a facade (a proxy, gateway or router) in front of the legacy application so every request passes through one place. Slice by slice you redirect routes to new services while everything else still reaches the old system. Feature-driven strangling picks slices by roadmap value. Security-driven strangling picks them by what an attacker touches first.

  • The facade is the whole trick. It decouples the caller from the implementation, so a slice can move without any client knowing it moved.
  • Slices are vertical. A slice owns its route, its logic and its data. Horizontal slicing leaves you with two half-systems, neither of which can ship on its own.
  • Order is a risk decision. The most valuable feature and the most dangerous code are rarely the same thing. Under a security mandate, dangerous wins.

Pick the first slice by blast radius, not by the backlog

Choose the slice that sits between the internet and your most sensitive data and that you cannot safely patch today. Rank candidates on three axes: exposure (reachable without credentials), exploitability (unsupported runtime, unmaintained dependency, no input validation) and blast radius (what it can read or write once it falls).

  • Anything built on a component in the CISA Known Exploited Vulnerabilities catalogue jumps the queue. That catalogue lists flaws with confirmed exploitation in the wild. If your stack contains one and no fix exists for your version, that is not technical debt, it is an open door.
  • Authentication is usually the correct first slice. It is small, it is reachable by everyone including attackers, and replacing it lets you introduce modern session handling and phishing-resistant MFA in one move. Credential stuffing and infostealer-driven session theft aim at exactly this surface.
  • Plugin-driven surfaces belong near the front. If your platform is a CMS carrying a decade of extensions, most of your exposure lives in code you did not write, which is the argument in The WordPress Security Reality Check Every Business Owner Avoids.
  • Do not start with the billing engine. Deep business logic with few external callers is the highest-effort, lowest-exposure slice on the board. It goes last, when the tooling is proven.

Build the facade first, and make it a control point

Install the routing layer in front of everything before you move any code, with every route still pointing at the legacy system. That release should change no observable behaviour. It gives you one place to terminate TLS, enforce rate limits, normalise requests and log every call, so risk starts falling before slice one exists.

  • One entry point, no exceptions. Any hostname, port or IP address that still reaches the legacy application directly will eventually be found and used. Close them at the firewall the same week.
  • Centralise request logging there. One consistent audit trail across both systems is what makes incident response possible while the estate is half-migrated.
  • The facade is your kill switch. When a new slice misbehaves in production, you route back to the old path in seconds instead of rolling back a release under pressure.
  • Never let the gateway be your only authorisation check. Broken object level authorisation leads the OWASP API Security Top 10 for good reason: the service behind the facade must independently verify that this caller may touch this object.

Keep both systems consistent without inventing a sync nightmare

Give every piece of data exactly one owner. Two designs are safe: the new slice owns its data and the legacy reads it through an API, or the legacy stays the owner and the new slice writes back through a narrow interface. Bidirectional synchronisation of the same records is where these projects die.

  • One writer per entity, always. If both systems can update a customer record, you will get silent overwrites, and the change that loses will be a permission change.
  • Share identity, not sessions. Issue one token format from the new authentication service, validate it at the facade and again inside each service. Two session stores means two places to get logout and expiry wrong.
  • Shadow the traffic before you flip. Send a copy of live requests to the new slice, compare responses, discard them. Differences that look cosmetic are often authorisation differences.

Make every slice ship a security upgrade, not just a rewrite

A straight port wastes the budget. Each slice must permanently remove a class of bug: parameterised queries instead of string-built SQL, output encoding by default, server-side authorisation on every object, secrets out of the repository, and logs that name the actor and the object. If a slice closes no control gap, redesign the slice.

  • Use the OWASP Top 10 as a per-slice acceptance checklist, not as an annual audit. The categories map onto code you can review while it is still being written.
  • Generate a software bill of materials for every new service. The CycloneDX format is machine-readable and broadly supported, so "which of our services contains that library" becomes a query rather than a fire drill.
  • Check each legacy dependency in the National Vulnerability Database before carrying it across. A library with no maintainer and no fixed version is a reason to redesign the slice. Abandoned packages are also the doorway for supply chain compromise and package confusion.
  • Kill the shared credential. Legacy systems usually have one database account with full rights, used by everything. Each new slice gets its own account and its own grants.
  • Write the tests that encode the rule. For every authorisation decision, add a test proving a different user is refused. Happy-path tests protect nothing.

Retire the old path deliberately

A strangler that never deletes code doubles your attack surface instead of reducing it. Retirement is a defined step with its own checklist: route removed, code deleted, service stopped, credentials rotated, database account dropped, DNS entry removed, firewall rule closed. Until every box is ticked, that slice is not migrated. It is duplicated.

  • Prove the old route is dead before cutting it. Log traffic still hitting the legacy handler and require a quiet period covering a full business cycle, month end and batch jobs included.
  • Assume someone will hunt for the bypass. The old hostname, the staging copy, the direct-to-origin IP address and the forgotten admin subdomain are standard targets, and exploitation of unpatched internet-facing services remains one of the most reliable ways in.
  • Rotate everything the retired code knew. API keys, database passwords, signing secrets, service accounts. Deleted code that still holds valid credentials is not deleted.
  • Keep the data, drop the running service. Archive to cold storage with its own access controls. A legacy database left online "just in case" is a breach on a timer.
  • URLs are part of retirement. Removing a public path without a redirect strategy costs traffic as well as trust, the discipline set out in Leaving WordPress: A Migration Playbook That Does Not Lose Your SEO.

What to measure while the migration runs

Track shrinkage, not velocity. Four numbers, reported monthly: share of traffic served by new slices, number of routes still reaching legacy code, number of legacy components past vendor support, and time to deploy a security fix in each system. The last one usually makes the business case unaided.

  • Traffic share beats story points. It tells an executive how much of the business now runs on supported code.
  • Time-to-patch is the honest measure. If a critical fix takes six weeks on the legacy path and two hours on the new one, you have quantified the risk carried by every remaining slice.
  • Publish a decommission date per slice. A slice without a retirement date is not planned, it is hoped for.

The failure modes that create a permanent hybrid

Three patterns account for most stalled migrations: no single owner for the facade, slices chosen by whoever complains loudest, and no funded decommissioning. All three end identically, in an estate with two of everything, two patch cycles, two log formats, and a security posture worse than the day you started.

How TuniCyberLabs helps

We run risk-ordered strangler migrations end to end: exposure assessment and slice ranking, facade design, slice-by-slice rebuild with a bill of materials and a control checklist per release, dual-run verification, and documented decommissioning so the old path genuinely disappears. Engineering in Tunisia, headquarters in Estonia, clients across the EU and North Africa.

Tell us the one system you are afraid to touch and we will come back with a ranked slice plan: see how we work.

TAGS
strangler patternlegacy modernisationsecurity debtapplication securityincremental migrationAPI gatewaytechnical debt

Frequently Asked Questions

What is the strangler pattern in software migration?

+

It is an incremental replacement strategy. You place a facade, usually a proxy or gateway, in front of the legacy application so every request passes through one point. You then rebuild one vertical slice at a time behind that facade and redirect its routes to the new service. The legacy system shrinks with each slice until nothing routes to it any more and you can switch it off.

How do I choose the first slice to migrate?

+

Rank candidates by exposure, exploitability and blast radius rather than by roadmap value. The winner is normally something reachable from the internet without credentials, running code you cannot patch, and able to read sensitive data. Authentication is a frequent first choice because it is small, universally reachable, and replacing it lets you introduce modern session handling and phishing-resistant MFA immediately.

Can both systems write to the same data during the migration?

+

Avoid it. Give every entity exactly one writer: either the new slice owns the data and the legacy reads it through an API, or the legacy stays the owner and the new slice writes through a narrow interface. Bidirectional synchronisation produces silent overwrites, and the write that loses is often a permission or ownership change nobody notices until an incident.

Is a strangler migration slower than a full rewrite?

+

It looks longer on paper and delivers value far sooner in practice. Each slice ships independently, so risk starts falling from the first release rather than at an uncertain launch date. A big-bang rewrite keeps the vulnerable system in production for the entire build, and a cancellation halfway leaves you with nothing. Strangling leaves you measurably better off at every stage.

When can we finally delete the legacy system?

+

When the retirement checklist is complete for every slice: routes removed, code deleted, service stopped, credentials rotated, database accounts dropped, DNS records removed and firewall rules closed. Confirm from logs that no traffic reached the old handler across a full business cycle, month end and batch jobs included. Archive the data to controlled cold storage, but never leave the old application running as a fallback.

What should each slice change besides the technology?

+

Each slice should permanently close a control gap, otherwise it is a rewrite with no security return. Expect parameterised queries, output encoding by default, server-side authorisation checked per object, secrets removed from source control, a dedicated database account with narrow grants, a software bill of materials, and audit logs that name both the actor and the object touched.

Need help with
this topic
?

Our team specializes in the technologies and strategies discussed in this article. Let’s talk about how we can help your business.

Get in Touch