apache/plc4x) — a multi-language library of client-side protocol drivers for industrial / OT (operational-technology) PLC protocols (Siemens S7, Modbus, EtherNet/IP, OPC UA, ADS/AMS, KNXnet/IP, BACnet/IP, IEC-60870-5-104, CANopen, C-Bus, Firmata, Profinet, UMAS, etc.) (documented: README.md, website/asciidoc/modules/users/pages/protocols/index.adoc).apache/plc4x repository only — driver layer, SPI, transports, code-generation runtime, and the four language bindings shipped here (plc4j, plc4go, plc4c, plc4py). The separately-released plc4x-extras repository (OPC-UA Server, PLC4X Server, Calcite / Camel / Kafka-Connect / Karaf / NiFi integrations, Connection-Cache, OPM, Scraper) is out of scope of this document (maintainer: Chris Dutz, 2026-05-29 16:06Z) and will be modelled separately if and when it is brought into the program.develop), HEAD 32b4f0c (“build(deps): bump jackson.version from 2.21.3 to 2.21.4” as of draft time). A vulnerability report against PLC4X release N is triaged against the model as it stood at N, not at HEAD.security@apache.org) per website/asciidoc/modules/users/pages/security.adoc; reports that fall under §3, §9, or §11a will be closed by PLC4X triagers citing this document.About the project. PLC4X provides a uniform client-side API (PlcConnection in Java; analogous in Go, C, Python) on top of a fleet of protocol drivers, each implementing one specific PLC wire protocol. An embedding application opens a connection by URL (e.g. s7://10.0.0.5:102?remote-rack=0&remote-slot=1, modbus-tcp://10.0.0.5:502, opcua:tcp://10.0.0.5:12686?discovery=true&security-policy=Basic256Sha256), optionally supplies a PlcAuthentication, and then issues read / write / subscribe / browse calls against tag-address strings whose syntax is protocol-specific (S7 area+offset, Modbus coil/register address, OPC UA ns=...;s=... node identifier, …). The library is a library — there is no daemon, no listening socket on the embedding side, no per-end-user identity. The “session” is the PLC connection.
PLC4X's domain is industrial network protocols. Most of these protocols were standardized in the 1980s–2000s before OT-network security was a design concern: Modbus, S7 (PUT/GET), BACnet/IP, IEC-60870-5-104, Profinet, CANopen, KNXnet/IP, C-Bus, DF1, AB-Ethernet, ADS/AMS, EtherNet/IP, and the historical UMAS dialect of Modicon all transit cleartext on the wire with no authentication, no integrity, and no confidentiality — that is the protocol as standardized, not a PLC4X choice. OPC UA, the youngest of the supported set, is the lone exception: it carries a full TLS-like security stack (certificates, signed/encrypted message exchange, security policies) and the OPC UA driver here actually implements that stack. This asymmetry shapes essentially every claim in the rest of the document.
README.md — “The Industrial IoT adapter”; website/asciidoc/modules/users/pages/protocols/index.adoc).plc4j/api/src/main/java/.../PlcConnection.java).PLC4X is not a network service. It is an in-process library built into a host application (Java, Go, C, or Python process). The host application — not PLC4X — is the thing exposed to its own users and to the wider IT network. PLC4X opens outbound connections to PLC endpoints; nothing in the main repo listens (documented: README.md, the plc4j/transports/ inventory which is exclusively client-side — tcp, udp, serial, raw-socket, pcap-replay, socketcan, can, virtualcan; no listener transport).
The library lives where the OT network meets the IT network: in typical deployments, the host process runs on a Linux/Windows VM or container with network reachability into the plant-floor / fieldbus segment, and surfaces data northbound by some other mechanism the host application chose. PLC4X has no opinion on the northbound side.
Because PLC4X is a library, there is no “client / operator / peer” role split of the kind a network service would have. The roles are:
| Role | Trust level | Notes |
|---|---|---|
| Embedding application | trusted — sole API caller | Decides which driver to load, supplies the connection URL, the PlcAuthentication (when the underlying protocol supports it), and every tag-address string. PLC4X has no notion of an “end user” within the embedding process (documented: plc4j/api/.../PlcConnection.java, PlcDriverManager.java). |
| Remote PLC device | untrusted on the wire | Industrial controllers in the field; the device‘s firmware, the wire bytes it emits, and any responses to PLC4X requests are all treated as untrusted input crossing a trust boundary into the library’s parser (inferred — §14 Q1). |
| OPC UA server | partially-authenticated peer | When OPC UA is the protocol, the server identity is bound to a certificate that PLC4X can verify against a trust store; that is the only protocol in the supported set where peer identity is cryptographic (documented: website/asciidoc/.../protocols/opcua.adoc; plc4j/drivers/opcua/.../security/). |
PLC4X server / OPC UA server (the embedding side of plc4x-extras) | out of scope — see §3 (maintainer) |
The main repo carves naturally into nine families with distinct threat profiles. Anything marked out below reappears in §3 with the reason.
| Family | Representative entry point | Touches outside the process? | In this model? |
|---|---|---|---|
Java public API (plc4j/api) | PlcDriverManager.getConnectionFactory().getConnection(url, auth) | no — pure dispatch | yes |
Java SPI / runtime (plc4j/spi) | AbstractPlcConnection, ConversationContext, Plc4xProtocolBase | no — orchestration | yes |
Per-protocol drivers (plc4j/drivers/{s7,modbus,opcua,ads,knxnetip,bacnet,c-bus,can,canopen,ctrlx,eip,firmata,iec-60870,logix,open-protocol,plc4x,profinet,profinet-ng,umas}) | one PlcDriver per protocol | yes — network, via the registered transport | yes |
Transports (plc4j/transports/{tcp,udp,serial,raw-socket,pcap-replay,pcap-shared,socketcan,can,virtualcan,test}) | Netty socket / serial / pcap | yes — sockets, serial devices, libpcap | yes |
OPC UA security subsystem (plc4j/drivers/opcua/.../security/, .../context/SecureChannel) | certificate verifier, security-policy negotiator, secure-channel encoder | yes — TLS-like primitives on the wire | yes — distinguished from other drivers; see §8 P1 |
Code-generation runtime (mspec read/write generators) under plc4j/.../readwrite/, plc4go/protocols/, plc4c/generated-sources/ | generated parsers / serializers | yes — driven by remote-PLC bytes | yes — same trust level as the driver that uses it |
Go bindings (plc4go/) | plc4go.NewPlcDriverManager() | as core | yes |
C bindings (plc4c/) | plc4c_* API | as core | yes — but README declares “not ready for usage” (documented: README.md) — see §3 |
Python bindings (plc4py/) | plc4py import | as core | yes — but README declares “not ready for usage” (documented: README.md) — see §3 |
.NET bindings (plc4net/) | n/a | n/a | out — README declares “not ready for usage - abandoned” (documented: README.md) |
PLC4X proxy driver (plc4j/drivers/plc4x) | plc4x:tcp://host/?remote-connection-string=... | network — outbound to a remote PLC4X server | yes for the client side; the server side is in plc4x-extras and out of scope (documented: website/.../protocols/plc4x.adoc) |
Simulated / mock drivers (plc4j/drivers/{simulated,mock}) | simulated://... | no | yes for code-quality; not a security surface |
Utilities (plc4j/utils/{pcap-replay,pcap-shared,plc-simulator,raw-sockets,test-generator,test-utils}) | dev tooling | varies | out — dev / test only (inferred — §14 Q2) |
Code-generation tooling under code-generation/ | mspec compiler invoked at build | host filesystem | out — build-time, not in the deployed artifact (inferred — §14 Q2) |
tools/, images/, media/, website/, licenses/, src/, .idea/, .github/, .mvn/, Dockerfile, docker-compose.yaml, Jenkinsfile | tooling, docs, build orchestration | n/a | out (inferred — §14 Q2) |
A finding is in-model only if it lands in a row marked “yes” — see §4 for the per-component reachability test.
PLC4X is not, and does not aim to be, the following — reports requiring any of these will be closed with the cited disposition.
website/.../protocols/*.adoc; inferred from the protocol specifications themselves — §14 Q3). A report of the shape “the wire payload is unauthenticated cleartext” or “anyone on the OT network can spoof a Modbus master” describes the protocol, not the library; PLC4X cannot add what the protocol does not have. → BY-DESIGN: protocol-disclaimed (§9). The integrator is responsible for the OT-network perimeter (§10). See §11a for the per-protocol enumeration.README.md, plc4j/api/.../PlcConnection.java — single connect/read/write/subscribe shape; transport inventory is exclusively client). Server / gateway functionality (OPC-UA Server, PLC4X Server, Calcite, Camel, Kafka-Connect, Karaf, NiFi adapters, Connection-Cache, OPM, Scraper) is published in the separate plc4x-extras repository (documented: README.md) and is explicitly out of scope of this document (maintainer: PMC chair, 2026-05-29 16:06Z). → OUT-OF-MODEL: unsupported-component.PlcAuthentication, every tag-address string, and every value written. Anything the embedding application could express via the public API is by definition authorized; “a malicious embedding application writes to the wrong coil” is not a PLC4X vulnerability (inferred — §14 Q4). → OUT-OF-MODEL: trusted-input.parseTagAddress is the embedding application's responsibility (inferred — §14 Q4). → OUT-OF-MODEL: trusted-input.%DB1.DBX0.0:BOOL, OPC UA ns=2;s=..., Modbus holding-register:40001:INT, …). If the embedding application accepts user-supplied tag strings, it is responsible for vetting them — the parser does not provide a security boundary against attacker-supplied tag strings (it provides a correctness boundary against malformed strings) (inferred — §14 Q5). → OUT-OF-MODEL: trusted-input for syntactic-validation reports, VALID for parser memory-corruption / DoS findings reachable from caller-supplied strings.plc4c/ and plc4py/ are flagged “not ready for usage” in README.md; plc4net/ is “not ready for usage - abandoned”; the tools/, code-generation/, plc4j/utils/, plc4j/drivers/{simulated,mock}, images/, media/, website/, licenses/, src/, top-level Dockerfile / docker-compose.yaml / Jenkinsfile are build, test, and documentation infrastructure (documented: README.md; inferred for the rest — §14 Q2). → OUT-OF-MODEL: unsupported-component.OUT-OF-MODEL: adversary-not-in-scope for device bugs; OUT-OF-MODEL: trusted-input for process-control consequences of an API-authorized write.OUT-OF-MODEL: adversary-not-in-scope.BY-DESIGN: property-disclaimed.PLC4X has two primary trust boundaries plus one optional cryptographic one for OPC UA. A finding is in-model only when it cleanly maps to one of them.
| # | Transition | Authentication | Authorization | Notes |
|---|---|---|---|---|
| B1 | Embedding application → PLC4X API surface | trusted by construction | the API caller is trusted | URL string, PlcAuthentication, tag-address strings, write values (documented) |
| B2 | PLC4X driver → remote PLC over the wire (Modbus, S7 PUT/GET, BACnet/IP, IEC-60870-5-104, Profinet, CANopen, KNXnet/IP, C-Bus, DF1, AB-Ethernet, EtherNet/IP, UMAS, ADS/AMS without credentials) | none — by protocol design (documented per protocol) | none on the wire; whatever the embedding application enforces | The OT-network perimeter is the only security control. Wire bytes returned to the driver are untrusted input crossing into the parser (inferred — §14 Q3). |
| B2-OPCUA | PLC4X OPC UA driver → OPC UA server (encrypted policy) | server cert verified against trust store (when trust-store-file is set); client cert optional; username/password or token over the encrypted channel | server-side ACLs | Mutually authenticated (cert + cert) and encrypted at the higher security policies; see §8 P1, §10 item 4 (documented: website/.../protocols/opcua.adoc, plc4j/drivers/opcua/.../security/) |
| B2-OPCUA-PERMISSIVE | OPC UA driver in default (no trust-store-file) mode | server certificates are not validated by default (documented: website/.../protocols/opcua.adoc — “Unless explicitly disabled through configuration of trust-store-file all server certificates will be accepted without validation”; plc4j/drivers/opcua/.../security/PermissiveCertificateVerifier.java) | n/a | This is the OPC UA driver's default behavior. See §5a “insecure-default case”. |
| B2-ADS | ADS driver → Beckhoff TwinCAT (AMS route setup with credentials) | username/password to the TwinCAT system for AMS-route setup, when a PlcUsernamePasswordAuthentication is supplied (documented: plc4j/drivers/ads/.../AdsProtocolLogic.java lines 130–145) | TwinCAT-side | The credentials are forwarded to the device; what the device does with them is outside PLC4X. ADS payload data itself is unauthenticated cleartext (inferred — §14 Q9). |
| B3 | PLC4X transport → host OS / NIC / serial port / libpcap | OS-level | OS-level | Whatever the embedding process's UID, capabilities, and seccomp / AppArmor profile permit. The raw-socket transport needs CAP_NET_RAW on Linux (inferred — §14 Q10). |
| B4 | Code-generation runtime → operating system at build time | n/a — only the developer runs this | n/a | Build-time only; not part of the deployed artifact (out per §3 item 6) |
For each family in §2, a finding is in-model only if it is reachable as follows.
readwrite/ parser code, OPC UA security subsystem: reachable from bytes the remote PLC (or attacker-on-the-OT-network) returns to the driver over the configured transport. The parser/decoder must not corrupt host memory, must not infinite-loop, must not allocate unboundedly, and must not cause the host process to crash on adversarial input (inferred — §14 Q11). This is the single most important reachability boundary in the document — most realistic PLC4X-side vulnerabilities will be wire-parser bugs.plc4j/api), SPI (plc4j/spi): reachable from the embedding application‘s calls. Memory-safety / correctness issues here are valid only if the embedding application’s call sequence is documented (per the Javadoc / the public Java API).*TagHandler, parseTagAddress): reachable from the tag-address string passed by the embedding application. PLC4X does not assume the string itself is attacker-controlled — see §3 item 5 — but a parser bug that corrupts memory or hangs the parser is still VALID-HARDENING (and VALID if the parser is memory-corrupting and the embedding application does pass user-controlled strings) (inferred — §14 Q5).plc4go/, plc4c/, plc4py/: per-language; the C and Python bindings are flagged “not ready for usage” in README.md — see §3 item 6 and §5a.README.md).--add-exports jdk.compiler/... for code generation but the runtime artifact does not (documented: README.md).plc4j/api/.../PlcDriverManager.java).malloc, or CPython allocator) provides the underlying memory model. PLC4X writes Java / Go / C / Python code at the language's normal trust level.PlcConnection is a Netty channel; calls through read/write/subscribe/browse return CompletableFutures. Thread safety is per the documented Java API contract (inferred — §14 Q12).plc4j/drivers/opcua/.../security/SecurityPolicy.java).plc4j/drivers/opcua/.../config/OpcuaConfiguration.java, plc4j/drivers/opcua/.../context/OpcuaDriverContext.java)..knxproj ETS files are parsed via XML; XXE / external-DTD / external-schema are explicitly disabled (documented: plc4j/drivers/knxnetip/.../ets/EtsParser.java lines 65–71 — factory.setFeature(DISALLOW_DOCTYPE_DECL, true) + FEATURE_SECURE_PROCESSING + empty ACCESS_EXTERNAL_DTD/SCHEMA).plc4j/drivers/bacnet/.../configuration/BacNetIpConfiguration.java).System.setSecurityManager, etc.) at runtime (inferred — §14 Q13);raw-socket transport does require CAP_NET_RAW (Linux) / Administrator (Windows) / root-equivalent privileges when used; this is a privileged transport with an inherent host-level cost the embedding application takes on by choosing it (inferred — §14 Q10).PLC4X exposes per-driver configuration knobs rather than a single global flag set. The security-relevant ones — those whose default value materially changes the security envelope — are collected here.
| Knob | Default | Maintainer stance | Effect |
|---|---|---|---|
OPC UA security-policy | NONE (documented: plc4j/drivers/opcua/.../config/OpcuaConfiguration.java) | maintainer ruling required — is “no encryption” a supported production posture, or dev-default? (inferred — §14 Q14) | If NONE, the OPC UA channel runs unencrypted and unauthenticated; B2-OPCUA collapses to B2 (cleartext). |
OPC UA message-security | SIGN_ENCRYPT (documented) | hardened default | When the security policy is not NONE, this forces sign-and-encrypt; flipping to SIGN (signed-cleartext) or NONE weakens the channel. |
OPC UA trust-store-file | unset (documented: website/.../protocols/opcua.adoc — “Unless explicitly disabled through configuration of trust-store-file all server certificates will be accepted without validation”; plc4j/drivers/opcua/.../security/PermissiveCertificateVerifier.java) | The OPC UA driver defaults to PermissiveCertificateVerifier — server certificates are accepted without validation. This is the single highest-priority maintainer ruling in the document. (inferred — §14 Q15) | Without a trust store, an MITM attacker on the OT network can present any certificate and the driver will trust it. Even with the security policy at Basic256Sha256 and SIGN_ENCRYPT, the encryption peer is unauthenticated. |
OPC UA key-store-file / key-store-password | unset (documented) | operator must supply for mutual-TLS-like client auth | If unset and a security policy ≠ NONE is configured, the driver auto-generates a self-signed client certificate (documented: website/.../protocols/opcua.adoc). Auto-generated certs are not recoverable across restarts; they cannot satisfy a peer that requires a known client identity. |
OPC UA discovery | true (documented) | enabled by default; the discovery phase is conducted with security policy NONE (documented: OpcuaConfiguration.java) | An attacker on the path between the driver and the discovery endpoint sees / can rewrite the advertised endpoint, security policies, and server certificate before the driver picks one. |
OPC UA username / password | unset (documented) | operator-supplied | Forwarded as the OPC UA UserIdentityToken; carried inside the secure channel when one exists, in cleartext otherwise. |
OPC UA channel-lifetime, session-timeout, negotiation-timeout, request-timeout | 1 h / 2 min / 60 s / 30 s (documented) | reasonable defaults | DoS / timeout-tuning surface; not a security boundary. |
ADS PlcUsernamePasswordAuthentication (when supplied) | unset (no AMS-route setup) | operator-supplied | When supplied, drives an AMS-route registration against the TwinCAT system using HTTP-style credentials (documented: plc4j/drivers/ads/.../AdsProtocolLogic.java). The credentials are not protected by PLC4X on the wire; TwinCAT-side TLS is the device's responsibility. |
BACnet/IP ede-file-path / ede-directory-path | unset | operator-supplied | If set, points at filesystem paths; standard file-permission rules apply. |
KNX .knxproj parser | XXE / external-DTD / external-schema disabled (documented: EtsParser.java) | hardened — this is the safe defaults case | Reports of the shape “XXE in .knxproj parsing” are KNOWN-NON-FINDING. |
S7 controller-type | unset (auto-discover via SZL) | operator-supplied for Siemens LOGO compatibility | Functional knob; not a security boundary. |
Modbus connection options (unit-id, byte order) | per spec | functional knobs | not security boundaries. |
plc4c/, plc4py/, plc4net/ builds | README declares these “not ready for usage” (with plc4net “abandoned”) (documented: README.md) | OUT-OF-MODEL for §8 properties; bugs reported against C / Python / .NET bindings should be triaged as code-quality / completeness, not as supported-product vulnerabilities until the maintainer reclassifies them | A finding in plc4c/ is OUT-OF-MODEL: unsupported-component until the README line changes. |
The OPC UA driver's defaults are dev/lab-grade, not production-grade: security-policy=NONE, trust-store-file unset, discovery=true over an unencrypted channel. Each of these defaults voids a §8 property the driver could otherwise provide. The §14 Q14, Q15, Q16 questions ask the maintainer to choose, per knob, between:
VALID against PLC4X, and the documentation needs to make clearer what the trade-off is, orOUT-OF-MODEL: non-default-build and the §10 contract makes the required knobs unambiguous.Both stances are defensible; the maintainer ruling determines which §13 disposition applies. The text of §10 items 4–6 is written on hypothesis (b) and will need adjustment if the maintainer chooses (a).
| Entry point | Parameter | Attacker-controllable? | Caller must enforce |
|---|---|---|---|
PlcDriverManager.getConnection(url, [auth]) | url | no — trusted caller string | only well-formed URLs reach this method; do not let end-users construct them |
PlcDriverManager.getConnection(url, auth) | auth (PlcAuthentication) | no — trusted caller object | credentials in the auth object are forwarded to the protocol (cleartext, except inside an OPC UA secure channel) |
connection.parseTagAddress(addr) | addr | conditionally — trusted by default; if the embedding application sources tag strings from end users, the embedding application is responsible (see §3 item 5; §14 Q5) | tag-address syntax validation; do not pass un-vetted untrusted strings |
readRequestBuilder.addTagAddress(name, addr) | addr | conditionally — same as above | as above |
writeRequestBuilder.addTagAddress(name, addr, value) | value | no — trusted caller value | application-level authorization over which tags may be written |
subscriptionRequestBuilder.add*(addr, ...) | addr | conditionally — same as above | as above |
| Surface | Parameter | Attacker-controllable? | Driver must enforce |
|---|---|---|---|
| Cleartext OT-protocol response (Modbus, S7, BACnet/IP, IEC-60870-104, Profinet, CANopen, KNXnet/IP, C-Bus, DF1, AB-Ethernet, ADS payload, EtherNet/IP, UMAS) | every byte of every response frame | yes — anyone on the OT network with reachability can spoof | memory safety, bounded allocation, no infinite loop, no unbounded recursion on malformed input — but not authenticity, integrity, or any payload-semantic guarantee (inferred — §14 Q11) |
| OPC UA wire frames inside the secure channel | every byte | yes — but signed/encrypted by the negotiated policy when policy ≠ NONE | as above plus: correct verification of signature and MAC under the negotiated policy; correct decryption; correct chunk reassembly (documented + inferred — §14 Q17) |
OPC UA wire frames during discovery (security-policy=NONE phase) | every byte | yes | memory safety on malformed responses; the discovery handshake itself is not authenticated (documented) |
| OPC UA server certificate (presented during handshake) | full DER bytes | yes | when trust-store-file is set: X.509 chain validation per JCE rules; when not set (default): none (documented: §5a) |
| Serial-line frames | every byte | yes if the serial channel is attacker-reachable | memory safety on malformed framing (inferred — §14 Q11) |
| libpcap capture / replay frames | every byte | yes if the capture file is attacker-controlled | the pcap-replay transport is a dev/test tool; if it's running in production, the integrator has put it there |
ETS .knxproj XML | as XML | yes if the file is attacker-supplied | XXE disabled (documented); ZIP slip protection — (inferred — §14 Q18) |
| BACnet EDE file | as text | yes if the file is attacker-supplied | parser robustness (inferred — §14 Q18) |
S7Configuration.pduSize, OpcuaConfiguration.limits.encoding.{send,receive}-buffer-size).read in a hot loop, the driver will issue as many requests as the underlying transport allows (inferred — §14 Q19).| Actor | In scope? | Capabilities granted |
|---|---|---|
| Network peer with reachability to the PLC (the OT network) | yes — primary adversary for B2 | can read, modify, drop, replay, or inject frames on the cleartext protocols. For the OPC UA protocol with a configured trust store, the peer is bounded by the cryptographic primitives. For OPC UA with the default PermissiveCertificateVerifier, the peer can MITM the channel. |
| Network peer between the driver and an OPC UA discovery endpoint | yes | the discovery handshake is unencrypted by spec (documented); the peer can swap the advertised endpoint URL, certificate, or set of supported policies. |
| Author of a malformed-but-parseable response from a real PLC firmware (buggy or compromised device firmware sending bytes a well-behaved firmware would not) | yes — wire-parser robustness must hold | causes the driver to parse adversarial bytes; in-model for memory safety, hang, unbounded allocation. |
Author of a malformed .knxproj or BACnet EDE file | yes for parser robustness | causes the offline-file parser to crash, hang, or escape from its expected sandbox (XXE blocked per §5a). |
| Embedding application itself | out of scope — see §3 item 3 | trusted by construction. |
| End user of the embedding application | out of scope — see §3 item 4 | PLC4X has no concept of an end user. |
| Operator of the PLC device | out of scope | the physical device the driver talks to is the device; PLC4X has no opinion on its operator. |
| Author of a tag-address string | conditionally in scope — see §3 item 5 | the embedding application decides whether to expose this surface. |
| Side-channel observer (cache timing, branch prediction, network timing of OPC UA crypto operations) | out of scope (inferred — §14 Q20) | standard JCE side-channel posture; no PLC4X-level constant-time guarantee. |
| Quantum adversary | out of scope | the OPC UA security policies in §5a use classical RSA / AES / SHA. |
PLC4X is a client-side library; there is no internal “cluster membership” to be Byzantine within. The closest analogue is a PLC device whose firmware has been compromised and which is sending crafted responses while passing whatever authentication the protocol provides. For cleartext protocols this is no different from any other attacker on the wire (§3 item 1); for OPC UA, this is the “compromised but properly-certified server” case — the driver still trusts the server's claims about data, even if the channel is cryptographically sound (inferred — §14 Q21). A finding requiring a compromised PLC to produce wrong measurement values is OUT-OF-MODEL: trusted-input (the device is the source of truth for its own data); a finding requiring a compromised PLC to crash or corrupt the driver via malformed wire bytes is in-model for memory safety.
For each property: condition, violation symptom, severity tier, provenance. There are fewer §8 properties than for a typical threat-model target precisely because PLC4X is a client-side library sitting on top of OT protocols that themselves provide little — most of the security work is delegated to the integrator (§10).
security-policy is set to one of Basic128Rsa15, Basic256, Basic256Sha256, Aes128_Sha256_RsaOaep, or Aes256_Sha256_RsaPss (documented: plc4j/drivers/opcua/.../security/SecurityPolicy.java), AND message-security is SIGN or SIGN_ENCRYPT (documented), AND trust-store-file is set to a trust store containing the expected server certificate (or its issuer) (documented: website/.../protocols/opcua.adoc).VALID per §13.trust-store-file is set; the trust store contains the expected certificate or a chain root (documented: website/.../protocols/opcua.adoc).VALID per §13.null where required, close() semantics observed.NullPointerException / IllegalStateException in PLC4X internals from a documented-correct API call (not a JVM crash — Java is GC'd); for the Go bindings, panic from an unsafe-free call site; for plc4c, native crash.malloc follows its documented semantics.StackOverflowError from unbounded recursion on a nested wire structure; in Go — goroutine hang, unbounded allocation; in C — heap / stack corruption, OOB read/write, use-after-free.VALID per §13.parseTagAddress / addTagAddress per the documented per-driver syntax.VALID-HARDENING by default (the address string is trusted per §6); VALID when the parser is reachable from unbounded user-supplied strings AND the embedding application's documented use of the API includes that case..knxproj parser.knxproj ETS file through the KNX driver.EtsParser resolves an external entity, external DTD, or external schema, allowing file-disclosure / SSRF from the .knxproj.VALID per §13.EtsParser.java lines 65–71). This is the one obvious “we hardened this” property in the repo and we cite it explicitly.NONE is selected.VALID per §13.website/.../protocols/opcua.adoc); a property break against those reference servers is a §8 P7 violation.These are the false-friend properties — features that look like a security property but are not one — and the well-known classes of attack the library cannot defend against. This section is the most important one for an integrator.
.knxproj ZIP slip, BACnet EDE malformed-file robustness, or path-traversal in operator-supplied file paths. The file paths are caller-supplied; XML XXE is the only attack class explicitly hardened (inferred — §14 Q18).website/.../protocols/opcua.adoc line 264) would assume the PLC4X OPC UA driver provides those properties by default. It does not. Defaults are security-policy=NONE (no encryption), no trust store (no server-identity validation), discovery over an unencrypted channel. All three must be flipped from default for the cryptographic story to mean what an OPC UA reader expects. (inferred — §14 Q14, Q15, Q16)security-policy=NONE. An attacker on the path during discovery can rewrite advertised endpoints, server certificates, and supported policies before the driver chooses what to honor. This is not a PLC4X bug; this is OPC UA (inferred — §14 Q16). But a scanner that reports “discovery handshake is unauthenticated” against PLC4X is reporting on the protocol, not on the driver (documented).:N is not “secure” because TCP is. The transport-level encryption is absent; the protocol-level encryption is absent. The protocol-spec authentication is either absent (Modbus) or weak (S7 PUT/GET (inferred — §14 Q23)) or device-specific (ADS/AMS route setup).simulated://, mock:// drivers are dev-tools, not sandboxes. They exist to let an embedding application be unit-tested without a real PLC; they are not isolation boundaries.pcap-replay transport is a developer / regression-test tool. It replays captured frames; it is not designed for production use and a finding against it that depends on an attacker controlling the pcap file is OUT-OF-MODEL: unsupported-component.plc4c/, plc4py/, plc4net/ are README-flagged “not ready for usage”. A finding against them is OUT-OF-MODEL: unsupported-component until the README line changes (§5a).PlcUsernamePasswordAuthentication on ADS / OPC UA carries credentials on the wire as the protocol dictates. It is not a PLC4X-level security primitive — it is a typed wrapper around two strings that the driver forwards to the protocol's authentication step. Whether it is then encrypted (OPC UA with a secure channel) or cleartext (ADS payload, OPC UA with security-policy=NONE) depends on the rest of the configuration.PlcCertificateAuthentication wraps an in-memory KeyStore for certificate-based authentication; the security properties of the surrounding TLS / OPC UA channel still apply..knxproj ZIP files. ZIP-slip in the unzip step is (inferred — §14 Q18)..knxproj. Mitigated by FEATURE_SECURE_PROCESSING (documented: EtsParser.java). → KNOWN-NON-FINDING.trust-store-file is unset (the default). Pending maintainer ruling (§14 Q15).read / subscribe requests. Out of model per §9 “No DoS protection at the API surface”.The embedding application / integrator deploying PLC4X in production must:
security-policy to Basic256Sha256 or stronger AND message-security to SIGN_ENCRYPT AND configure a trust-store-file that contains only the expected server certificate or its issuing CA. The default of “NONE, no trust store” is not the production posture (inferred — §14 Q14, Q15).key-store-file / key-store-password. The auto-generated self-signed certificate the driver falls back to is not recoverable across restarts and cannot satisfy a peer that requires a stable client identity (documented: website/.../protocols/opcua.adoc).discovery and configure the endpoint explicitly via endpoint-host, endpoint-port. The discovery handshake is unauthenticated by OPC UA spec (documented).raw-socket transport requires CAP_NET_RAW (or Administrator) — grant it to the embedding process specifically rather than running as root. (integrator)simulated://, mock://, pcap-replay drivers as dev / test fixtures, not as production endpoints. (integrator)plc4c/, plc4py/, or plc4net/ artifacts in production until the README line (“not ready for usage”) is removed. (integrator; documented: README.md)security-policy=NONE in production. The default. → §9 false-friend item 1.trust-store-file. The driver uses PermissiveCertificateVerifier by default — every server certificate is accepted. An MITM gets the encryption key. → §5a.discovery=true as part of the security boundary. Discovery is over security-policy=NONE by OPC UA spec. → §9 false-friend.simulated:// or mock:// in production code paths. They are dev tools.parseTagAddress without vetting. A parser bug becomes a user-reachable bug.plc4c/ or plc4py/ artifact in production. The README flags them.PlcCertificateAuthentication without TLS / OPC UA secure channel underneath. The KeyStore exists; the credential is there; whether anything on the wire is actually encrypted depends on the surrounding configuration.--add-exports jdk.compiler/... flags in the production JVM. Those flags are for the build, not the runtime artifact (documented: README.md); granting them at runtime exposes JDK internals unnecessarily.This section is the highest-leverage input for automated agentic security scans. Each entry: tool symptom, why it is safe under the model, the § that licenses the call. PLC4X‘s §11a is unusually long because the project’s core domain is unauthenticated OT protocols, and a scanner unaware of that fact will report essentially every wire-format property of every driver.
BY-DESIGN: protocol-disclaimed.BY-DESIGN: protocol-disclaimed.website/.../protocols/s7.adoc — “S7-300/S7-400 controllers, as well as basic reading and writing functions for the S7-1200 and S7-1500 devices (PUT/GET functions)”). → §3 item 1, §9. BY-DESIGN: protocol-disclaimed.BY-DESIGN.BY-DESIGN.BY-DESIGN.BY-DESIGN.BY-DESIGN.BY-DESIGN.BY-DESIGN.PermissiveCertificateVerifier); the §10 item 3 contract requires the operator to set trust-store-file. Maintainer ruling (chrisdutz, §14 Q15): this default “should be changed and reported” — it is not the supported posture, so a report is VALID (a gap the PMC intends to fix toward secure-by-default), not OUT-OF-MODEL: non-default-build.key-store-file is unset (website/.../protocols/opcua.adoc). The auto-generated cert is intended as a “get-it-working” convenience; production should provision an explicit one. → §10 item 4. OUT-OF-MODEL: non-default-build pending §14 Q14.Basic128Rsa15/Basic256 policies which are deprecated by the OPC Foundation.” Yes — the driver supports them (documented: SecurityPolicy.java) because some PLC firmware still only supports them. The operator is responsible for choosing Basic256Sha256 or stronger per §10 item 3 (inferred — §14 Q25). → OUT-OF-MODEL: non-default-build.EtsParser.java lines 65–71). → KNOWN-NON-FINDING.plc4j/utils/test-utils/, tests/, testdata/, simulated://, mock:// drivers.” These are test infrastructure. → §3 item 6. OUT-OF-MODEL: unsupported-component.plc4c/ / plc4py/ / plc4net/.” README flags these as not-ready. → §3 item 6. OUT-OF-MODEL: unsupported-component pending the README line being removed.code-generation/ mspec compiler has X.” Build-time only, not in the runtime artifact. → §3 item 6. OUT-OF-MODEL: unsupported-component.Dockerfile, docker-compose.yaml, Jenkinsfile has X.” Repo infrastructure. → §3 item 6.plc4x-extras). → §3 item 2. OUT-OF-MODEL: unsupported-component.OUT-OF-MODEL: unsupported-component (inferred — §14 Q26).CAP_NET_RAW.) OUT-OF-MODEL: adversary-not-in-scope.OUT-OF-MODEL: adversary-not-in-scope.OUT-OF-MODEL: trusted-input.Revise this document when any of the following lands:
security-policy, trust-store-file, or message-security.plc4c/, plc4py/, or plc4net/ has its “not ready for usage” README flag removed — those move from §3 item 6 to in-model.plc4x-extras shifts (e.g. an integration is brought back into the main repo, or vice versa).A report against PLC4X receives exactly one of the following.
| Disposition | Meaning | Licensed by |
|---|---|---|
VALID | Violates a §8 property via an in-scope §7 adversary using an in-scope §6 input — typically a wire-parser memory-safety break (P4), an OPC UA secure-channel break (P1/P2/P7), or KNX-XML XXE bypass (P6). | §8, §6, §7 |
VALID-HARDENING | No §8 property violated, but a §11 misuse pattern can be made harder to fall into by code change (e.g. issue a runtime warning when OPC UA runs security-policy=NONE). Fixed at maintainer discretion, typically no CVE. | §11 |
OUT-OF-MODEL: trusted-input | Requires attacker control of a §6 parameter the model marks trusted — the connection URL, the auth object, the value being written, tag-address strings (per §3 item 5 when the integrator has not opted them into untrusted-string handling). | §6 |
OUT-OF-MODEL: adversary-not-in-scope | Requires a §7 actor the model excludes — embedding application is hostile, side-channel observer, quantum adversary, OT-network perimeter is the integrator's problem. | §7 |
OUT-OF-MODEL: unsupported-component | Lands in plc4c/, plc4py/, plc4net/, tools/, code-generation/, plc4j/utils/, plc4j/drivers/{simulated,mock}, plc4x-extras content, vendored upstream code, or repo infrastructure. | §3 item 2, §3 item 6 |
OUT-OF-MODEL: non-default-build | Only manifests under a §5a knob the maintainer has ruled is dev/test. Note: per the maintainer (chrisdutz, §14 Q14/Q15/Q16) the OPC UA insecure defaults are moving to secure-by-default — the permissive certificate verifier in particular is a gap to fix (VALID), not a non-default-build exclusion. | §5a |
BY-DESIGN: protocol-disclaimed | Concerns a property the protocol (not the library) does not provide — every “Modbus / S7 / BACnet / etc. is unauthenticated” report. | §9, §3 item 1, §11a |
BY-DESIGN: property-disclaimed | Concerns a §9 property the library explicitly does not provide (built-in TLS tunneling, end-user authn, DoS protection at the API). | §9 |
KNOWN-NON-FINDING | Matches a §11a recurring false positive. | §11a |
MODEL-GAP | Cannot be cleanly routed to any of the above — triggers §12 model revision. | §12 |
Every (inferred) tag in the body maps to one of these. Proposed answers are inline; please confirm, correct, or strike.
PMC review (chrisdutz, 2026-06-04, PR-approved): the OPC UA insecure defaults (Q14/Q15/Q16) are moving to secure-by-default — the permissive certificate verifier in particular is a gap to fix, not a supported posture — and the SPI3 rewrite adds TLS transport, hardens the parsers, and bounds per-connection allocation (Q8/Q11/Q18/Q19). Answers folded below and into the body as (maintainer).
Q1. Confirm that “remote PLC bytes on the wire are untrusted input crossing into the parser” is the right framing for §2 / §4 — i.e., the driver's job is to be memory-safe and bounded-resource against any byte sequence a remote PLC (or attacker on the OT net) could send, even though the protocol itself provides no authentication. (maps to §2, §4 B2, §7, §8 P4)
Q2. Confirm the unsupported-component list: plc4j/utils/, plc4j/drivers/{simulated,mock}, code-generation/, tools/, images/, media/, website/, licenses/, top-level Dockerfile/docker-compose.yaml/Jenkinsfile. Anything to add or remove? (maps to §3 item 6)
Q3. Confirm the per-protocol enumeration of “no auth / no integrity / no confidentiality” in §3 item 1 and §11a. The proposed list: Modbus (all variants), S7 (PUT/GET), BACnet/IP (classic), IEC-60870-5-104, Profinet (the variant implemented), CANopen, KNXnet/IP (classic), C-Bus, DF1, AB-Ethernet, EtherNet/IP (classic CIP), UMAS, ADS/AMS payload, Open-Protocol, Firmata. Have we missed any, or wrongly tarred one that does have some authentication the driver enforces? (maps to §3 item 1, §11a)
Q4. Confirm “the embedding application is trusted, end users of the embedding application are out of scope” (proposed: yes). Are there any embedded-product / OEM contexts where PLC4X considers the embedding application's end users in scope? (maps to §3 items 3, 4)
Q5. Tag-address strings: confirm the default stance is “trusted caller input — embedding application owns vetting”. Is there a PLC4X-side memory-safety / hang / unbounded-allocation guarantee on tag-address strings? Proposed: VALID-HARDENING for parser robustness, VALID only if the embedding application's documented contract includes user-supplied strings. (maps to §3 item 5, §8 P5)
Q6. Confirm out-of-scope status of PLC-device firmware bugs and physical-process consequences. (maps to §3 item 7)
Q7. OT-network perimeter as integrator responsibility — confirm the §10 item 1 framing. (maps to §3 item 8, §10)
Q14. OPC UA security-policy=NONE default. Is “OPC UA used with security-policy=NONE in production” a VALID report against PLC4X (stance (a) — default is supported posture) or OUT-OF-MODEL: non-default-build (stance (b) — operator must flip per §10 item 3)? Proposed: (b) — the default is convenience for dev/lab. If (a), the documentation needs to make clear that “OPC UA” with this driver does not by default carry OPC UA's spec-level cryptographic properties.
Answered (maintainer — chrisdutz): secure-by-default is the intended posture — the SPI3 rewrite makes the insecure path explicitly opt-in and the secure path the new default; the current NONE default is dev/lab convenience, not a supported production posture. (maps to §5a, §10, §11a, §13)
Q15. OPC UA default PermissiveCertificateVerifier — the single highest-priority question. When trust-store-file is unset, the driver accepts every server certificate. Is “OPC UA driver accepts attacker-presented certificate” VALID (stance (a)) or OUT-OF-MODEL: non-default-build (stance (b))? Answered (maintainer — chrisdutz): the permissive default “should be changed and reported” — it is not the supported posture. A report that the OPC UA driver accepts an attacker-presented certificate is therefore VALID (a security gap the PMC intends to fix toward secure-by-default), not OUT-OF-MODEL: non-default-build. (maps to §5a, §10 item 3, §11a, §13)
Q16. OPC UA discovery=true over security-policy=NONE. The spec mandates discovery in cleartext; the driver follows the spec. Confirm that “OPC UA discovery handshake unauthenticated” is BY-DESIGN: protocol-disclaimed per §9 false-friend item 2 — not a PLC4X bug.
Answered (maintainer — chrisdutz): confirmed — cleartext discovery is per the OPC UA spec (BY-DESIGN: protocol-disclaimed); separately, the broader OPC UA channel is moving to secure-by-default in SPI3 (see Q14/Q15). (maps to §3 item 1, §9, §10 item 5)
Q11. Confirm §8 P4 (memory safety, bounded allocation, bounded loop / recursion in per-driver wire parsers on adversarial wire bytes) is a property PLC4X has actually committed to — i.e., a Modbus parser that allocates O(N) memory in response to a 1-byte length field with no upper bound is a bug, not “just OT-protocol weirdness”. Are there specific drivers where this property has been deliberately weakened (e.g. generated code that is faster but not bounded)?
Answered (maintainer — chrisdutz): P4 is committed; in the SPI3 rewrite each connection allocates a fixed-length ring-buffer (length varying per protocol), preventing the “huge fake message → huge allocation” class of issue. (maps to §4 reachability, §8 P4, §11a)
Q17. OPC UA secure-channel implementation correctness — §8 P1 / P2 / P7. Are these properties tested against the cited reference servers (Eclipse Milo, OPC Foundation .NET) on every release, or only manually at version-bump time? Are there OPC UA test vectors (spec-published handshake traces) the driver is regressed against? (maps to §8 P1, P2, P7)
Q18. .knxproj (ZIP) handling: confirm ZIP-slip protection in the unzip step. BACnet EDE files: confirm parser robustness against malformed files.
Answered (maintainer — chrisdutz): the SPI3 rewrite addresses the ETS-parser issues and hardens XML parsing. (maps to §6, §9, §11a)
Q19. No API-level throttle confirmed? Proposed: yes — the embedding application is responsible.
Answered (maintainer — chrisdutz): confirmed — no API-level throttle; the embedding application is responsible. (SPI3's per-connection ring-buffer additionally bounds per-connection allocation.) (maps to §6, §9, §10 item 8)
Q20. Side-channel posture for OPC UA crypto: out of scope (proposed). (maps to §7, §9)
Q21. Compromised PLC firmware sending crafted but spec-compliant responses — confirm the split: wrong measurement values are OUT-OF-MODEL: trusted-input (the device is the source of truth), but wrong wire framing is in-model for parser robustness. (maps to §3 item 7, §7, §8 P4)
Q22. §8 P3 (Java/Go/C-binding API memory safety): is the right framing “Java public API is memory-safe by virtue of being Java, unless a JNI path is reached”, or do you make a stronger claim? (maps to §8 P3)
Q8. External tunneling (VPN / IPSec / TLS-wrap) is integrator‘s responsibility — confirm §9 / §10 item 2. Is there appetite for a “TLS-wrap transport” that would terminate at PLC4X (e.g. Modbus-over-TLS per Schneider Electric’s draft spec)? If yes, that changes §12.
Answered (maintainer — chrisdutz): yes — the SPI3 rewrite adds tls and tls-psk transports that can secure a tcp connection where the target PLC/gateway supports it. This is a §12-changing addition. (maps to §9, §10 item 2, §12)
Q9. ADS authentication: when PlcUsernamePasswordAuthentication is supplied, the credential drives an AMS-route registration (AdsProtocolLogic lines 130–145). Confirm that this is forwarded in whatever transport mode TwinCAT runs (typically cleartext); PLC4X does not encrypt it. (maps to §4 B2-ADS, §5a)
Q10. raw-socket transport requires CAP_NET_RAW — confirm this is the only transport with elevated host-privilege needs. Any others? (maps to §3, §10 item 9)
Q12. Thread-safety of PlcConnection: confirm the documented contract (proposed: connections are not safe for concurrent use by multiple threads without the embedding application‘s own synchronization; the CompletableFuture model returns to the caller’s thread). (maps to §5)
Q13. Confirm the “what PLC4X does NOT do to its host” inventory in §5: no signal handlers (besides Netty / JVM), no child-process spawn at runtime, no listening sockets, no security-sensitive env-var reads, no global-state mutation. Any exceptions? (maps to §5)
Q23. S7 PUT/GET vs S7 protected modes: the docs reference “S7-Plus” as a future target. The current driver speaks PUT/GET exclusively (documented: website/.../protocols/s7.adoc). Confirm that “S7 password protection on the PLC” (the device-side PG / OS access password) is out-of-band to the driver — the driver will speak PUT/GET to whatever device responds. (maps to §3 item 1, §9, §11a)
Q24. KNX Secure: is the KNX driver implementing KNX Secure (the cryptographic overlay on KNXnet/IP), or only classic KNXnet/IP? Proposed: only classic. (maps to §11a)
Q25. OPC UA legacy policies (Basic128Rsa15, Basic256): deprecated by the OPC Foundation but supported here for PLC-firmware compat. Confirm the stance: supported for connectivity reasons, operator chooses Basic256Sha256-and-up per §10 item 3. (maps to §5a, §10 item 3, §11a)
Q26. Vendored / dependency CVEs (Netty, Jackson, Eclipse Milo crypto, commons-*) — confirm the policy is “report upstream, PLC4X picks up the fix via the next dependency bump”. (maps to §3 item 6, §11a)
Q27. Should this document live at docs/threat-model.md / website/asciidoc/modules/users/pages/threat-model.adoc, or somewhere else? (meta)
Q28. Is there an existing threat-model document (Confluence wiki, internal note) that this should reconcile against rather than supersede? The website security.adoc page is process-only (where to report); the developers/maturity.adoc page references the security process but has no threat-model content. (meta — §3.1a of the rubric)
Q29. plc4x-extras boundary: confirm that this document is strictly for the main apache/plc4x repo and that a separate model will be produced for plc4x-extras when that repo is brought into the program. (maps to §1, §3 item 2)
Q30. §11a is the highest-leverage section for automated triage and is heavily protocol-disclaimer-shaped here. Could the PMC contribute 3–5 patterns observed in inbound reports / mailing-list threads that recur — e.g. “scanner reports unauthenticated Modbus, we close every time”; “scanner reports plaintext password in OPC-UA-over-security-policy=NONE, we close every time”? Concrete recurring false-positives strengthen the suppression list. (meta — §11a)
Q31. What kind of change to PLC4X should trigger a revision (proposed list in §12 — confirm or correct)? (meta, §12)
PLC4X does not currently ship an in-repo SECURITY.md. The de facto security-policy artefacts are:
website/asciidoc/modules/users/pages/security.adoc — the process-only page, which says (verbatim): “For more information about reporting vulnerabilities, see the Apache Security Team page. … No vulnerabilities have been reported.” No threat-model content; everything maps to the §1 reporting cross-reference.website/asciidoc/modules/developers/pages/maturity.adoc — restates the process posture (QU20, QU30); no threat-model content.website/asciidoc/modules/users/pages/protocols/*.adoc — these are the best documented sources for protocol-level security caveats. The back-map below covers the load-bearing ones.| Source | Claim | Lands in |
|---|---|---|
README.md (“plc4c/, plc4py/ not ready for usage; plc4net/ abandoned”) | scope carve-out | §3 item 6, §5a |
README.md (“The Industrial IoT adapter … client-side library across multiple PLC protocols”) | scope framing | §2 |
website/.../protocols/opcua.adoc (“Unless explicitly disabled through configuration of trust-store-file all server certificates will be accepted without validation”) | default-permissive verifier | §4 B2-OPCUA-PERMISSIVE, §5a, §9 false-friend item 1, §11a |
website/.../protocols/opcua.adoc (“discovery phase is always conducted using NONE security policy” — paraphrased from OpcuaConfiguration.java discovery doc) | discovery unencrypted | §4 B2-OPCUA-PERMISSIVE, §9 false-friend item 2 |
website/.../protocols/opcua.adoc (“message-security … SIGN_ENCRYPT … high security settings and full encryption”) | secure-channel message security | §5a, §8 P1 |
website/.../protocols/opcua.adoc (“There is transport level certificate which can be provided though keystore options, but there is also a X509 Certificate which can be used for authentication (currently unsupported by PLC4X)”) | client-X509-auth not implemented | §11a, §14 Q14 |
website/.../protocols/opcua.adoc (compatibility list: Eclipse Milo, OPC Foundation .NET, etc.) | tested reference servers | §8 P7 |
website/.../protocols/s7.adoc (“PUT/GET functions”) | S7 mode | §3 item 1, §11a, §14 Q23 |
website/.../protocols/s7.adoc (“Siemens LOGO device … requires ?controller-type=LOGO”) | functional knob | §5a (non-security row) |
website/.../protocols/modbus.adoc (no security section) | Modbus is unauthenticated | §3 item 1, §11a (disclaimer-by-omission) |
website/.../protocols/canopen.adoc (“CANopen … address areas”) | CANopen scope | §3 item 1, §11a |
website/.../protocols/ads.adoc (“device-independent and fieldbus independent interface for communication between Beckhoff automation devices”) | ADS scope | §3 item 1, §11a |
website/.../protocols/index.adoc | per-language driver-coverage matrix | §2 component table |
website/asciidoc/.../security.adoc (“For more information about reporting vulnerabilities, see the Apache Security Team page”) | reporting channel | §1 reporting cross-reference |
website/asciidoc/.../developers/maturity.adoc (QU20, QU30) | maturity posture | §1 reporting cross-reference |
plc4j/drivers/opcua/.../security/PermissiveCertificateVerifier.java (no-op checkCertificateTrusted) | implements the default | §4 B2-OPCUA-PERMISSIVE, §5a |
plc4j/drivers/opcua/.../security/SecurityPolicy.java (enum of NONE, Basic128Rsa15, Basic256, Basic256Sha256, Aes128_Sha256_RsaOaep, Aes256_Sha256_RsaPss) | supported policies | §5a, §8 P1, P7, §11a, §14 Q25 |
plc4j/drivers/opcua/.../config/OpcuaConfiguration.java (@ConfigurationParameter set incl. trust-store-file, discovery, username, password, key-store-file, key-store-password, security-policy=NONE, message-security=SIGN_ENCRYPT, channel-lifetime=3600000, session-timeout=120000, negotiation-timeout=60000, request-timeout=30000) | knob inventory | §5a, §6, §10 |
plc4j/drivers/knxnetip/.../ets/EtsParser.java lines 65–71 (XXE/DTD/schema disabled, FEATURE_SECURE_PROCESSING) | hardened XML parser | §5 (filesystem-KNX), §8 P6, §11a code-base |
plc4j/drivers/ads/.../AdsProtocolLogic.java lines 130–145 (PlcUsernamePasswordAuthentication instance check; setupAmsRoute(...) call) | ADS credential forwarding | §4 B2-ADS, §5a |
plc4j/api/.../authentication/PlcAuthentication.java, PlcUsernamePasswordAuthentication.java, PlcCertificateAuthentication.java | auth type-system | §6, §9 false-friend |
plc4j/api/.../PlcConnection.java, PlcDriverManager.java | public API surface | §2, §4 B1, §6 |
plc4j/transports/{tcp,udp,serial,raw-socket,pcap-replay,socketcan,can,virtualcan,test} (no listening-socket entries) | client-only transports | §2, §3 item 2, §10 item 9 |