~/blog/running-end-of-life-drupal-beside-current-drupalPOSTED
by Shady Nathan Tawfik · July 11, 2026 · 4 min

The Legacy Instance Beside The Modern One Is The Real Estate

One organisation ran two generations of a content platform simultaneously. The modern one was current; the legacy one defined the risk, including a client library past end of life.

Interactive[blog-2.0]

TL;DR: Two generations of one platform on one domain: the modern one was current, the legacy one defined the risk, and the parent cookie scope tied them together. I show how I mapped both estates and how to retire the archive.

The scenario

I ran this as a black-box review: no credentials, only the publicly visible surface. Here is what I saw before I touched anything.

A community and events platform with a current content management system on the main domain and a legacy installation of the same platform serving an archived section on a subdomain, fronted by a caching layer. Scope covered both estates, the shared cookie scope, client library versions and subdomain exposure.

I removed all identifying information. The target is described only by sector and technology class so the pattern can be reused.

The pattern

The pattern I recognised — and that I keep finding in similar estates:

Coexisting generations is normal and it is where technical debt becomes an attack surface. When a current platform handles the site and a legacy platform handles an archive, both are reachable, both share a domain, and both receive requests from the same audience. The legacy one has no maintainers watching it, no patch cadence and a smaller user base to notice a breach, which is precisely why it is not upgraded.

Two amplifiers make this worse. First, the cache: a layer that stores and serves responses can hide an old platform from casual inspection, so the estate looks current to everyone including the team. Second, the cookie scope: a cookie set on the parent domain is sent to every host beneath it, so an attacker who obtains a session cookie from the legacy host can present it to the modern one, and a session established on the legacy host is trusted by shared middleware.

The third amplifier is the client library. Long-dead platforms ship long-dead libraries that other sites still use, so their end-of-life status affects third parties who never chose it. That is why an unmaintained installation is a supply chain problem, not only a hygiene problem.

TL;DR: One organisation ran two generations of a content platform simultaneously. The modern one was current; the legacy one defined the risk, including a client library past end of life.

Findings

SeverityFindingEvidence
HOCHLegacy platform still served on a subdomainArchived section on a platform release past end of life
HOCHClient library version past end of lifeAffects third-party sites that did not choose the dependency
MEDIUMCookie scope shared across both platformsSession from the legacy host valid on the modern host
MEDIUMCaching layer hides the legacy platform from inspectionEstate appears current to automated checks
LOWEnumerated subdomains with distinct stacksSeveral technologies on one domain
LOWAdministrative paths reachable on both estatesConsistent attack surface instead of one hardened point

The attack path

hidesShared parent domainCurrent platformLegacy platform subdomainCookie sent to every hostSession cookie obtained on legacy hostPresented to current platformCaching layer

Reproduction in my lab

Every command below targets a lab container I control. Nothing here is aimed at a live system.

Map the generations on your own estate

~/code/bash bash
# what answers where, including archived sections
$ for h in example.org www.example.org archive.example.org old.example.org legacy.example.org; do
    printf '%-28s %s  %s\n' "$h" \
      "$(curl -so /dev/null -w '%{http_code}' https://$h/)" \
      "$(curl -sI https://$h/ | grep -i '^x-powered-by\|^x-generator\|^server:' | head -1 | tr -d '\r')"
done

# is the parent cookie shared
$ curl -sI https://example.org/ | grep -i '^set-cookie'

Detection in your own estate

Check what your own client libraries have reached end of life

~/code/bash bash
$ npm outdated --json 2>/dev/null | python3 -c '
import json,sys
d = json.load(sys.stdin)
for name, info in d.items():
    cur, want = info.get("current"), info.get("wanted")
    print(f"{name}: {cur} -> {want}")' | head -30

# and list every host you actually own
$ for h in $(cat hosts.txt); do
    printf '%s %s\n' "$h" "$(dig +short "$h" | tr '\n' ' ')"
done

Remediation

Scope the session cookie to the host that needs it

~/code/nginx nginx
# no session cookie for the whole estate
proxy_cookie_path / /;
proxy_cookie_domain example.org ~^([a-z0-9-]+\.)?example\.org$ localhost;

# better: set the cookie host-only by never setting a domain attribute
add_header Set-Cookie "sessionid=; Path=/; Secure; HttpOnly; SameSite=Lax" always;

Once an attacker gains access, they can perform the following actions:

Legacy platform still served on a subdomain
Client library version past end of life
Cookie scope shared across both platforms
Caching layer hides the legacy platform from inspection

Takeaways

  • Two generations on one domain means two attack surfaces and one cookie scope.
  • A cache that hides an old platform hides it from your own audits too.
  • An unmaintained platform is a third-party dependency problem, not just yours.
  • Retire the archive by redirecting it; every year it runs is a year of exposure.

For educational purposes only. Every reproducible command targets my own lab environment (localhost), never a live system. © 2026