# PLC / SPS Projects (CODESYS)
Certifai analyzes industrial control logic (IEC 61131-3) for PLC/SPS targets such
as CODESYS projects. A single PLC/SPS target is treated as a **composite device**:
the control application *and* the device it runs on.
| What you provide | What Certifai does |
| --- | --- |
| PLC project (PLCopen XML / ST, or a `.projectarchive`) | **Control-logic SAST** — semantic security rules over ST **and** graphical FBD/LD |
| A `.projectarchive` | **Control-app SBOM** — the referenced CODESYS libraries + the runtime version, matched against known CVEs |
| A device firmware image | Firmware SBOM / CVE (opt-in) |
| A reachable endpoint (WebVisu, OPC UA) | DAST / pentest (opt-in) |
## Anatomy: a soft PLC is a SoC + Linux + runtime
A CODESYS controller is **not** a monolithic appliance like a classic Siemens
S7. It is **PC-based ("soft") control** — commodity silicon running a
general-purpose Linux, with a **software PLC runtime** as just another process:
| Classic PLC (e.g. Siemens S7) | Soft PLC (CODESYS-on-Yocto, OpenPLC-on-Raspbian) |
| --- | --- |
| Proprietary hardware + firmware | Commodity SoC (x86 / ARM) |
| Proprietary OS | General-purpose Linux (a **Yocto** image, or Raspbian) |
| Proprietary runtime | Software runtime (**CODESYS Control**, or OpenPLC) |
| STEP7 / TIA project | IEC 61131-3 control app (ST / LD / FBD / SFC) |
Because of this, the device is built along **two independent tracks**, by
different people, on different timelines, and shipped separately. It also
inherits the **entire Linux / IT attack surface on top of** the OT / control
one — which is exactly why a PLC/SPS target is treated as a **composite**:
Certifai ingests one artifact per layer and scans each with the right pipeline.
```mermaid
flowchart TB
subgraph TA["Track A · Device platform — built by the hardware OEM / vendor"]
direction LR
A1["Yocto / OpenEmbedded
BSP + RT kernel"] --> A2["Bake in the CODESYS
Control for Linux runtime"] --> A3["bitbake → device image
.wic / .tar + manifest"]
end
subgraph TB2["Track B · Control application — built by the machine builder / customer"]
direction LR
B1["CODESYS IDE
ST / LD / FBD / SFC + WebVisu"] --> B2["Reference CODESYS +
vendor libraries"] --> B3["Compile → download
to device (gateway 11740)"]
end
A3 --> DEV(["Running soft-PLC device
SoC + Linux + runtime + control app
Modbus · OPC UA · EtherNet/IP · WebVisu"])
B3 --> DEV
subgraph CERT["What Certifai scans — one layer per artifact"]
direction LR
S1["Firmware layer
FirmwareStatic · SBOM · CVE"]
S2["Control-logic layer
PLC SAST — ST + FBD/LD"]
S3["Control-app SBOM
libraries + runtime → CVE"]
S4["Running layer
ICS probe · DAST (WebVisu)"]
end
A3 -. firmware image .-> S1
B1 -. PLCopen XML / ST via git .-> S2
B2 -. projectarchive (zip) .-> S3
DEV -. live URL / provisioned .-> S4
classDef yocto fill:#fde68a,stroke:#b45309,color:#111
classDef codesys fill:#bfdbfe,stroke:#1d4ed8,color:#111
classDef dev fill:#e9d5ff,stroke:#7e22ce,color:#111
classDef cert fill:#bbf7d0,stroke:#15803d,color:#111
class A1,A2,A3 yocto
class B1,B2,B3 codesys
class DEV dev
class S1,S2,S3,S4 cert
```
::: tip Where Yocto fits
Yocto is **Track A** — the *build system* for the device platform. It produces
the Linux image and bakes in the CODESYS runtime, so it is the **firmware
layer**, entirely separate from the control application. Hand it to Certifai as
its own **firmware image** artifact (scanned by the firmware pipeline, not the
PLC pipeline). The device OS need not be Yocto — Raspbian/Debian/Buildroot, or
even an RTOS / bare-metal, are all possible — but Yocto is the common,
product-grade industrial choice.
:::
## Two ways to deliver the project
You can either **upload** the project when onboarding, or point Certifai at a
**git repository** (recommended — every scan is just a `git pull`, no re-upload).
### Option A — Upload
On the onboarding wizard, choose target type **PLC / SPS**, then attach a **PLC
project** artifact and pick its format:
- **PLCopen XML** (`.xml`) — export from CODESYS via *Project → Export PLCopenXML*.
- **Structured Text** (`.st`) — a raw ST file.
- **Project archive** (`.projectarchive`) — *File → Project Archive → Save/Send
Archive…* with **"Referenced libraries"** ticked. This is the only form that
also yields the **library + runtime SBOM**.
### Option B — Git repository (recommended)
Attach a **Git repository** artifact to the PLC/SPS target. Certifai clones it and
runs the control-logic scan over the exported source in the repo.
## Best-case git repository layout
Because the binary `.project` does not diff or merge in git, commit **textual
exports** for review-friendly SAST, and include the **`.projectarchive`** so the
library/runtime SBOM is available too:
```text
my-plc-project/
├── src/
│ ├── PLC_PRG.xml # PLCopen XML export (ST or FBD/LD) — one per POU
│ ├── PumpController.xml
│ ├── SafetyInterlock.xml
│ └── GVL.xml # global variable lists, also as PLCopen XML
├── PumpStation.projectarchive # optional but recommended → library + runtime SBOM
└── README.md
```
**Guidelines**
- **Export to PLCopen XML** (`Project → Export PLCopenXML`), one file per POU, and
commit those. ST, **and graphical FBD/LD**, are both analyzed.
- Alternatively commit raw `.st` / `.exp` / `.scl` files — also analyzed.
- **Do not** commit only the binary `.project` — it cannot be parsed (and does not
diff). If you want the library SBOM, commit the **`.projectarchive`** as well.
- CODESYS's built-in Git integration, which stores an exported representation,
works too — as long as the committed form is PLCopen XML / textual.
::: tip What unlocks what
- **Control-logic SAST** needs textual source in the repo (PLCopen XML or `.st`).
- **Library + runtime SBOM** needs a **`.projectarchive`** — PLCopen XML exports do
**not** carry the referenced libraries.
:::
## What the scanner finds
The control-logic rules are CWE-mapped and include: hardcoded credentials
(CWE-798), default/weak passwords (CWE-1393), safety interlock / watchdog bypass
(CWE-1384), unchecked array indexing (CWE-129), division-by-zero (CWE-369,
guard-aware), cleartext/insecure communication (CWE-319), insecure protocol ports
(CWE-319, e.g. Modbus 502, FTP 21, Telnet 23), and unstructured jumps (CWE-691).
The **SBOM** view lists the CODESYS libraries (`pkg:codesys/@`) and
the runtime; matching runtime components (e.g. the `Cmp*` / `3SLicense` libraries)
surface real CODESYS advisories as CVE alerts.
## Dynamic testing — ICS protocol probe
Beyond the static analysis, Certifai can **probe the running device** over
industrial protocols. Attach a **Live URL** artifact (the device host / WebVisu
URL) to the PLC/SPS target and enable the **ICS Probe** scan.
The probe is **read-only** — it never writes to the live process. It currently
speaks **Modbus/TCP** (port 502): it confirms whether the device answers
unauthenticated Modbus requests and reads its device identity (vendor / product /
revision). Because Modbus/TCP has no authentication or encryption in the protocol,
a reachable endpoint that answers is reported as an exposed control interface
(CWE-306). OPC UA and EtherNet/IP probes are planned.
::: warning
The ICS probe connects to the live device. It is **opt-in** (off by default) and
should only be run against targets you are authorized to test. It performs reads
only, never writes.
:::