Back to blog

Cyberattack on French Supermarket Fridges: IoT Security Lessons in 2026

Hello HaWkers, on Sunday night, October 11, 2026, hundreds of supermarkets in France woke up to refrigerators and freezers out of service. The attackers did not steal card data or demand a cryptocurrency ransom: they remotely triggered the automatic defrost cycle on the refrigeration controllers. The result: fresh and frozen stock thrown away, an investigation opened by the Paris prosecutor's office, and reports of fires in some stores.

Have you ever stopped to think about how many "dumb" devices in your company are actually connected to the internet through a forgotten web panel? In this article we will look at what is known so far about the attack, which known flaws exist in this kind of controller, and above all what you, as a developer or infrastructure person, can do first thing tomorrow so you are not the next case.

What Happened in the French Supermarkets

According to BleepingComputer, the attackers struck overnight and hijacked refrigeration controllers running old versions of control software from Danfoss, the Danish manufacturer of refrigeration and climate equipment. Instead of shutting the machines down, they fired the automatic defrost cycle, a legitimate function that heats the evaporator to melt accumulated ice. Left on for hours, that cycle makes the display case temperature climb until everything inside spoils.

The numbers vary by source, so they deserve a careful look:

  • Intermarché and Netto: at least 300 stores hit, according to AFP
  • Coopérative U: more than 100 locations affected
  • E.Leclerc: several stores, and the chain confirmed that the attack hit one of its refrigeration equipment suppliers
  • Carrefour: the company spoke of 80 supermarkets attacked, out of a total of around 6,000 stores
  • Monoprix and Carrefour Market were mentioned by industry sites, but without official confirmation at first

French outlets estimated between 250 and 350 affected stores, while the sum of the figures released by the chains themselves goes beyond that. CNBC reported equipment heating up to 50 °C. The president of Coopérative U, Dominique Schelcher, called the attack "unprecedented" and said it targeted equipment essential to keeping fresh products. Intermarché said the affected stores would have to discard all fresh and frozen products.

The Response from Danfoss and the French Government

Danfoss stated that most of the affected equipment consisted of "legacy" products, which no longer receive software or security updates. The company named the AK-SM800 and AK-SC355 controllers and said that one version of the AK-SM800 was running outdated firmware. According to the manufacturer, supermarkets had long been advised to upgrade these models.

On the government side, a person close to Prime Minister Sébastien Lecornu said that France's national cybersecurity agency (ANSSI) had already identified "a vulnerability in software supplied by a Danish company", contacted the vendor, and is coordinating the response with European agencies. The Paris prosecutor's office opened an investigation into the "large-scale cyberattack" that hit refrigerators at several food retail chains, with the goal of identifying the victims and linking the attack to the food losses and the reported fires.

The European Commissioner for Agriculture, Christophe Hansen, wrote on X that "food security requires more attention at all levels". As of this writing, no perpetrator has been officially identified. The political context helps explain the tension: the month before, President Emmanuel Macron had ordered measures to protect the country's critical infrastructure against Russian "hybrid attacks". But connecting one thing to the other is, for now, speculation.

On the same day, Dutch group Ahold Delhaize said it had taken some systems offline because of a "cybersecurity incident". So far, there is no evidence that the two cases are connected.

Why This Is No Surprise to Anyone Who Works with IoT

If you follow industrial systems security, the attack is frightening because of its scale, not its method. Back in February 2019, TechCrunch was already reporting internet-connected industrial refrigeration controllers that could be defrosted remotely because they still used the factory default password. Seven years later, the pattern repeats.

Danfoss controllers from the AK-SM 800A family also have a recent history of documented flaws. Researchers from Claroty Team82 published three vulnerabilities, fixed in firmware R4.3.1:

  • CVE-2025-41450: a hidden authentication mechanism called "code-of-the-day". The controller generates a daily password from the current date; by reconstructing the algorithm, an attacker could bypass the configured administrator password.
  • CVE-2025-41451: command injection in the SMTP settings. The email authentication password was assembled into a shell command without sanitization, opening the door to remote code execution.
  • CVE-2025-41452: injection of directives into the Nginx headers file by an authenticated user, taking down the management service (denial of service).

Important: so far, no official source has confirmed that these CVEs were used in the French attack. They do, however, show the kind of attack surface this equipment exposes when it is reachable from the internet.

And the exposure is real. A Censys scan cited at the time of disclosure found 2,765 devices with an interface reachable from the internet. After the attack, Baptiste Robert, CEO of Predicta Lab, counted 2,752 exposed Danfoss systems, 1,590 of them in France. BleepingComputer also cites more than 4,500 Danfoss devices tracked by Shodan.

The underlying problem is familiar to anyone who has worked with operational technology (OT): the equipment lasts 10 or 15 years, the manufacturer stops supporting it well before that, and the web panel a technician opened "just to access it from home" stays open long after everyone has forgotten it exists.

Step 1: Find Out What You Have Exposed

You cannot protect what you do not know about. The first step is an inventory of your own public addresses, looking for management interfaces that should not be there. The script below runs a simple check on IPs that belong to your organization and looks for common signatures of embedded device panels.

# inventario_exposicao.py
# Checks whether YOUR organization's public IPs respond with management
# panels of embedded devices. Use only on assets you own.
import socket
import requests
import urllib3

urllib3.disable_warnings()  # many devices use self-signed certificates

MEUS_IPS = ["203.0.113.10", "203.0.113.11"]  # replace with your IPs
PORTAS = [80, 443, 8080, 8443]
ASSINATURAS = ["danfoss", "ak-sm", "ak-sc", "refrigeration", "hvac", "xweb"]

def porta_aberta(ip: str, porta: int, timeout: float = 2.0) -> bool:
    """Returns True if the TCP port accepts a connection."""
    try:
        with socket.create_connection((ip, porta), timeout=timeout):
            return True
    except OSError:
        return False

def checar(ip: str, porta: int) -> None:
    esquema = "https" if porta in (443, 8443) else "http"
    try:
        resp = requests.get(f"{esquema}://{ip}:{porta}/", timeout=4, verify=False)
    except requests.RequestException:
        return
    corpo = resp.text.lower()
    achados = [a for a in ASSINATURAS if a in corpo]
    if achados:
        # Any finding here is an OT panel reachable from the internet
        print(f"[ALERTA] {ip}:{porta} parece expor gerenciamento: {achados}")

for ip in MEUS_IPS:
    for porta in PORTAS:
        if porta_aberta(ip, porta):
            checar(ip, porta)

This script does not replace a professional scanner, but it handles the most common case: discovering that the "store 42" IP responds with the refrigeration controller's login screen. If you have an account on services like Shodan or Censys, it is also worth searching for your company's IP blocks and seeing what the rest of the world already sees.

Step 2: Compare Firmware Against the Minimum Safe Version

After the inventory, the next step is to know which devices are below the patched version. For the AK-SM 800A, the public reference is firmware R4.3.1. The example below reads an inventory CSV and flags what needs an update or, worse, what no longer has any update available.

# auditoria_firmware.py
# Reads the equipment inventory and flags firmware below the minimum safe version.
import csv
import re

# Minimum version per model; None = legacy product with no fix available
MINIMO_SEGURO = {
    "AK-SM800A": "4.3.1",
    "AK-SM800": None,   # legacy: isolate or replace
    "AK-SC355": None,   # legacy: isolate or replace
}

def normalizar(versao: str) -> tuple[int, ...]:
    """Converts 'R4.3.1' or '4.3.1' into (4, 3, 1) for comparison."""
    numeros = re.findall(r"\d+", versao)
    return tuple(int(n) for n in numeros)

with open("inventario.csv", newline="", encoding="utf-8") as arquivo:
    # Expected columns: loja,modelo,firmware,ip_interno
    for linha in csv.DictReader(arquivo):
        modelo = linha["modelo"].strip().upper()
        if modelo not in MINIMO_SEGURO:
            continue
        minimo = MINIMO_SEGURO[modelo]
        if minimo is None:
            print(f"[LEGADO] {linha['loja']}: {modelo} sem suporte -> isolar da rede")
        elif normalizar(linha["firmware"]) < normalizar(minimo):
            print(f"[ATUALIZAR] {linha['loja']}: {modelo} em {linha['firmware']} (mínimo {minimo})")

Notice that the most serious case is not outdated firmware, it is legacy equipment. For it, there is no fix. The only defense is to put the device out of reach of anyone who should not touch it.

Step 3: Isolate Legacy Equipment from the Internet

A refrigeration controller does not need to answer any IP on the planet. It needs to talk to the company's monitoring system and, occasionally, to the maintenance technician. That fits in a firewall rule. Below is an example with nftables on a Linux gateway that separates the OT VLAN from the rest of the network:

# /etc/nftables.d/ot-refrigeracao.nft
# Refrigeration controllers live on VLAN 30 (10.30.0.0/24).
# Only the maintenance VPN and the monitoring server can reach them.

table inet ot_refrigeracao {
  chain forward {
    type filter hook forward priority 0; policy drop;

    # Keep already established connections
    ct state established,related accept

    # Maintenance VPN (10.99.0.0/24) accesses the web panel
    ip saddr 10.99.0.0/24 ip daddr 10.30.0.0/24 tcp dport { 443 } accept

    # Monitoring server collects telemetry
    ip saddr 10.10.0.5 ip daddr 10.30.0.0/24 tcp dport { 443, 502 } accept

    # Controllers DO NOT initiate connections to the internet
    ip saddr 10.30.0.0/24 log prefix "OT-SAIDA-BLOQUEADA " drop
  }
}

Three decisions make the difference here. The default policy is drop, so anything not explicitly allowed stays out. Remote access goes through a VPN with strong authentication, never through an open port on the router. And outbound traffic from the controllers to the internet is blocked and logged, which helps detect a compromised device trying to talk to the outside.

If you work with cloud services, the reasoning is the same one we saw in botnet attacks using AWS infrastructure: whatever is exposed by default ends up being found by someone.

Step 4: Monitor Behavior, Not Just Access

Even with a segmented network, it is worth having an alarm that fires when the equipment does something out of the ordinary. In the French attack, the signal was there: defrost cycles outside the scheduled window and temperatures rising in many stores at the same time. The following script analyzes telemetry readings and raises an alert in both scenarios.

# alerta_degelo.py
# Detects defrost outside the scheduled window and abnormal heating of display cases.
from datetime import datetime, time
from collections import defaultdict

# Scheduled defrost windows (example: 2 a.m. and 2 p.m., 30 minutes each)
JANELAS_DEGELO = [(time(2, 0), time(2, 30)), (time(14, 0), time(14, 30))]
LIMITE_CONGELADOS_C = -12.0   # above this, alert for frozen goods
LIMITE_LOJAS_SIMULTANEAS = 3  # several stores at once = possible attack

def dentro_da_janela(instante: datetime) -> bool:
    agora = instante.time()
    return any(inicio <= agora <= fim for inicio, fim in JANELAS_DEGELO)

def analisar(leituras: list[dict]) -> None:
    """Each reading: {'loja', 'equipamento', 'instante', 'temp_c', 'degelo_ativo'}"""
    lojas_suspeitas = defaultdict(list)
    for l in leituras:
        instante = datetime.fromisoformat(l["instante"])
        if l["degelo_ativo"] and not dentro_da_janela(instante):
            lojas_suspeitas[l["loja"]].append(f"degelo fora da janela em {l['equipamento']}")
        if l["equipamento"].startswith("congelado") and l["temp_c"] > LIMITE_CONGELADOS_C:
            lojas_suspeitas[l["loja"]].append(f"{l['equipamento']} a {l['temp_c']} °C")

    for loja, motivos in lojas_suspeitas.items():
        print(f"[ALERTA] loja {loja}: {'; '.join(motivos)}")

    # Many stores at once point to coordinated action, not an isolated defect
    if len(lojas_suspeitas) >= LIMITE_LOJAS_SIMULTANEAS:
        print(f"[CRÍTICO] {len(lojas_suspeitas)} lojas com anomalia simultânea: acionar resposta a incidente")

The most important detail is at the end: one broken freezer is maintenance; thirty freezers warming up on the same night is a security incident. Correlating events across locations is what turns operational telemetry into attack detection.

What This Teaches Anyone Who Writes Software

It may look like a problem only for the people who run supermarket networks, but the lessons apply to anyone who writes software that controls something physical, from a smart lock to an IoT dashboard built with JavaScript:

  1. "Magic" passwords are security debt. The "code-of-the-day" behind CVE-2025-41450 is a support shortcut that became a backdoor. If your product has maintenance access, it needs a unique credential per device and a usage log.
  2. Never build a shell command from user input. CVE-2025-41451 is the classic case: an SMTP password field concatenated into a command. Use your language's APIs with an argument list, never a single string.
  3. Plan for the product's end of life. Equipment that stays in the field for 15 years needs a plan for when support ends: a safe offline mode, disabling the remote panel, or a clear notice to the customer.
  4. Legitimate functions can become weapons too. Defrost is a normal function. What was missing was limits: how long it can stay active, who can trigger it off schedule, and what happens if the temperature goes past the safe point.

That last point is the most interesting one from an engineering standpoint. A well-designed controller could refuse a defrost that kept frozen goods above a threshold for too long, regardless of who issued the command. Safety interlocks on the device itself protect you even when authentication fails.

Outlook: Food Security Has Become a Cybersecurity Topic

The French attack is likely to speed up a conversation the retail sector has been postponing. In the European Union, the NIS2 directive already extends cybersecurity obligations to sectors considered essential, and Commissioner Hansen's remarks suggest the food chain will get more attention. On the manufacturer side, the pressure will be to keep support going longer and to eliminate hidden access mechanisms.

For people who work in tech, the message is practical: take inventory of what is exposed today, isolate what cannot be patched, and create alerts that watch how the equipment behaves. None of these steps requires a huge budget, but all of them require someone to remember that the fridge is also a computer.

Let's go! 🦅

📚 Want to Keep Up With What Is Coming?

This article covered the attack on French supermarket fridges and how to protect industrial IoT, but the ecosystem changes every week, and not everything becomes an article here.

On X, I share what I am testing, behind-the-scenes notes from my projects, and news that appears before it becomes a blog post.

Follow Me There

👉 Follow @jeffbruchado on X

💡 Daily content about development, careers, and the tools I actually use

Comments (0)

This article has no comments yet 😢. Be the first! 🚀🦅

Add comments